@plune-ai/cli 0.34.4 → 0.34.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 +116 -3
- package/THIRD_PARTY_NOTICES +41 -0
- package/dist/cli.cjs +5150 -520
- package/dist/index.cjs +2 -2
- package/dist/index.js +2 -2
- package/dist/mcp-tools.cjs +20 -4
- package/dist/mcp-tools.d.cts +6 -0
- package/dist/mcp-tools.d.ts +6 -0
- package/dist/mcp-tools.js +20 -4
- package/dist/reporter-core.cjs +1 -1
- package/dist/reporter-core.js +1 -1
- package/package.json +6 -3
package/dist/index.cjs
CHANGED
|
@@ -1891,8 +1891,8 @@ function gateExit(verdict, runnerCode) {
|
|
|
1891
1891
|
if (counts == null) return { code: 1, line: "plune: gate failed \u2014 no verdict from the platform, and no verdict is no pass." };
|
|
1892
1892
|
const n = (status) => counts[status] ?? 0;
|
|
1893
1893
|
const notRun = verdict?.notRun?.length ?? 0;
|
|
1894
|
-
if (
|
|
1895
|
-
return { code: runnerCode, line: `plune: gate \u2014 no result reached the run, so the exit code is the command's own (${runnerCode}).` };
|
|
1894
|
+
if (notRun === 0 && Object.values(counts).every((k) => !k)) {
|
|
1895
|
+
return runnerCode !== void 0 ? { code: runnerCode, line: `plune: gate \u2014 no result reached the run, so the exit code is the command's own (${runnerCode}).` } : { code: 1, line: "plune: gate failed \u2014 no result reached the run, so there is nothing to pass." };
|
|
1896
1896
|
}
|
|
1897
1897
|
const said = `${n("failed")} failed \xB7 ${n("broken")} broken \xB7 ${notRun} not run \xB7 ${n("muted")} muted`;
|
|
1898
1898
|
return n("failed") + n("broken") > 0 || notRun > 0 ? { code: 1, line: `plune: gate failed \u2014 ${said}` } : { code: 0, line: `plune: gate passed \u2014 ${said}` };
|
package/dist/index.js
CHANGED
|
@@ -1831,8 +1831,8 @@ function gateExit(verdict, runnerCode) {
|
|
|
1831
1831
|
if (counts == null) return { code: 1, line: "plune: gate failed \u2014 no verdict from the platform, and no verdict is no pass." };
|
|
1832
1832
|
const n = (status) => counts[status] ?? 0;
|
|
1833
1833
|
const notRun = verdict?.notRun?.length ?? 0;
|
|
1834
|
-
if (
|
|
1835
|
-
return { code: runnerCode, line: `plune: gate \u2014 no result reached the run, so the exit code is the command's own (${runnerCode}).` };
|
|
1834
|
+
if (notRun === 0 && Object.values(counts).every((k) => !k)) {
|
|
1835
|
+
return runnerCode !== void 0 ? { code: runnerCode, line: `plune: gate \u2014 no result reached the run, so the exit code is the command's own (${runnerCode}).` } : { code: 1, line: "plune: gate failed \u2014 no result reached the run, so there is nothing to pass." };
|
|
1836
1836
|
}
|
|
1837
1837
|
const said = `${n("failed")} failed \xB7 ${n("broken")} broken \xB7 ${notRun} not run \xB7 ${n("muted")} muted`;
|
|
1838
1838
|
return n("failed") + n("broken") > 0 || notRun > 0 ? { code: 1, line: `plune: gate failed \u2014 ${said}` } : { code: 0, line: `plune: gate passed \u2014 ${said}` };
|
package/dist/mcp-tools.cjs
CHANGED
|
@@ -467,7 +467,15 @@ var PLUNE_TOOLS = [
|
|
|
467
467
|
}),
|
|
468
468
|
output: import_zod2.z.object({
|
|
469
469
|
revealed: import_zod2.z.array(import_zod2.z.string()),
|
|
470
|
-
available: import_zod2.z.array(
|
|
470
|
+
available: import_zod2.z.array(
|
|
471
|
+
import_zod2.z.object({
|
|
472
|
+
name: import_zod2.z.string(),
|
|
473
|
+
title: import_zod2.z.string(),
|
|
474
|
+
description: import_zod2.z.string(),
|
|
475
|
+
write: import_zod2.z.boolean(),
|
|
476
|
+
inputSchema: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.unknown()).optional().describe("JSON Schema of the arguments, where the tool list is fixed and a tool is called by its name")
|
|
477
|
+
})
|
|
478
|
+
),
|
|
471
479
|
visible: import_zod2.z.array(import_zod2.z.string())
|
|
472
480
|
}),
|
|
473
481
|
write: false,
|
|
@@ -563,6 +571,7 @@ function defaultVisibleTools(scope) {
|
|
|
563
571
|
|
|
564
572
|
// src/mcp-tools/execute.ts
|
|
565
573
|
var import_node_crypto = require("crypto");
|
|
574
|
+
var import_zod3 = require("zod");
|
|
566
575
|
|
|
567
576
|
// src/mcp-tools/client.ts
|
|
568
577
|
var PluneApiError = class extends Error {
|
|
@@ -871,11 +880,18 @@ function createPluneToolExecutor(opts) {
|
|
|
871
880
|
if (unknown.length > 0) return fail("invalid_input", `No such tool: ${unknown.join(", ")}. Call this tool without names to see what there is.`);
|
|
872
881
|
const refused = names.filter((n) => scope === "read" && pluneTool(n).write);
|
|
873
882
|
if (refused.length > 0) return fail("read_only_token", readScopeMessage(`${refused.join(", ")} cannot be switched on`));
|
|
874
|
-
|
|
883
|
+
const fixed = opts.fixedToolList === true;
|
|
884
|
+
if (!fixed) for (const n of names) revealed.add(n);
|
|
875
885
|
const words = (i["query"] ?? "").toLowerCase().split(/\s+/).filter(Boolean);
|
|
876
886
|
const visible = visibleTools();
|
|
877
|
-
const available = PLUNE_TOOLS.filter((t) => !visible.includes(t.name) && !(scope === "read" && t.write)).filter((t) => words.every((w) => `${t.name} ${t.title} ${t.description}`.toLowerCase().includes(w))).map((t) => ({
|
|
878
|
-
|
|
887
|
+
const available = PLUNE_TOOLS.filter((t) => !visible.includes(t.name) && !(scope === "read" && t.write)).filter((t) => words.every((w) => `${t.name} ${t.title} ${t.description}`.toLowerCase().includes(w))).map((t) => ({
|
|
888
|
+
name: t.name,
|
|
889
|
+
title: t.title,
|
|
890
|
+
description: t.description,
|
|
891
|
+
write: t.write,
|
|
892
|
+
...fixed ? { inputSchema: import_zod3.z.toJSONSchema(t.input, { target: "draft-2020-12", io: "input" }) } : {}
|
|
893
|
+
}));
|
|
894
|
+
return { revealed: fixed ? [] : names, available, visible };
|
|
879
895
|
},
|
|
880
896
|
async plune_cases_update(i) {
|
|
881
897
|
const cases = i["cases"];
|
package/dist/mcp-tools.d.cts
CHANGED
|
@@ -676,6 +676,7 @@ declare const PLUNE_TOOLS: readonly [{
|
|
|
676
676
|
title: z.ZodString;
|
|
677
677
|
description: z.ZodString;
|
|
678
678
|
write: z.ZodBoolean;
|
|
679
|
+
inputSchema: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
679
680
|
}, z.core.$strip>>;
|
|
680
681
|
visible: z.ZodArray<z.ZodString>;
|
|
681
682
|
}, z.core.$strip>;
|
|
@@ -903,6 +904,11 @@ interface PluneToolExecutorOptions {
|
|
|
903
904
|
fetchImpl?: typeof fetch | undefined;
|
|
904
905
|
userAgent?: string | undefined;
|
|
905
906
|
now?: (() => number) | undefined;
|
|
907
|
+
/**
|
|
908
|
+
* The client's tool list never changes: discover_tools switches nothing on and describes the hidden tools with their
|
|
909
|
+
* input schemas, and a hidden tool is called by its name. MCP 2026-07-28 asks this of tools/list.
|
|
910
|
+
*/
|
|
911
|
+
fixedToolList?: boolean | undefined;
|
|
906
912
|
}
|
|
907
913
|
interface PluneToolExecutor {
|
|
908
914
|
readonly sessionId: string;
|
package/dist/mcp-tools.d.ts
CHANGED
|
@@ -676,6 +676,7 @@ declare const PLUNE_TOOLS: readonly [{
|
|
|
676
676
|
title: z.ZodString;
|
|
677
677
|
description: z.ZodString;
|
|
678
678
|
write: z.ZodBoolean;
|
|
679
|
+
inputSchema: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
679
680
|
}, z.core.$strip>>;
|
|
680
681
|
visible: z.ZodArray<z.ZodString>;
|
|
681
682
|
}, z.core.$strip>;
|
|
@@ -903,6 +904,11 @@ interface PluneToolExecutorOptions {
|
|
|
903
904
|
fetchImpl?: typeof fetch | undefined;
|
|
904
905
|
userAgent?: string | undefined;
|
|
905
906
|
now?: (() => number) | undefined;
|
|
907
|
+
/**
|
|
908
|
+
* The client's tool list never changes: discover_tools switches nothing on and describes the hidden tools with their
|
|
909
|
+
* input schemas, and a hidden tool is called by its name. MCP 2026-07-28 asks this of tools/list.
|
|
910
|
+
*/
|
|
911
|
+
fixedToolList?: boolean | undefined;
|
|
906
912
|
}
|
|
907
913
|
interface PluneToolExecutor {
|
|
908
914
|
readonly sessionId: string;
|
package/dist/mcp-tools.js
CHANGED
|
@@ -431,7 +431,15 @@ var PLUNE_TOOLS = [
|
|
|
431
431
|
}),
|
|
432
432
|
output: z2.object({
|
|
433
433
|
revealed: z2.array(z2.string()),
|
|
434
|
-
available: z2.array(
|
|
434
|
+
available: z2.array(
|
|
435
|
+
z2.object({
|
|
436
|
+
name: z2.string(),
|
|
437
|
+
title: z2.string(),
|
|
438
|
+
description: z2.string(),
|
|
439
|
+
write: z2.boolean(),
|
|
440
|
+
inputSchema: z2.record(z2.string(), z2.unknown()).optional().describe("JSON Schema of the arguments, where the tool list is fixed and a tool is called by its name")
|
|
441
|
+
})
|
|
442
|
+
),
|
|
435
443
|
visible: z2.array(z2.string())
|
|
436
444
|
}),
|
|
437
445
|
write: false,
|
|
@@ -527,6 +535,7 @@ function defaultVisibleTools(scope) {
|
|
|
527
535
|
|
|
528
536
|
// src/mcp-tools/execute.ts
|
|
529
537
|
import { createHash, randomBytes, randomUUID } from "crypto";
|
|
538
|
+
import { z as z3 } from "zod";
|
|
530
539
|
|
|
531
540
|
// src/mcp-tools/client.ts
|
|
532
541
|
var PluneApiError = class extends Error {
|
|
@@ -835,11 +844,18 @@ function createPluneToolExecutor(opts) {
|
|
|
835
844
|
if (unknown.length > 0) return fail("invalid_input", `No such tool: ${unknown.join(", ")}. Call this tool without names to see what there is.`);
|
|
836
845
|
const refused = names.filter((n) => scope === "read" && pluneTool(n).write);
|
|
837
846
|
if (refused.length > 0) return fail("read_only_token", readScopeMessage(`${refused.join(", ")} cannot be switched on`));
|
|
838
|
-
|
|
847
|
+
const fixed = opts.fixedToolList === true;
|
|
848
|
+
if (!fixed) for (const n of names) revealed.add(n);
|
|
839
849
|
const words = (i["query"] ?? "").toLowerCase().split(/\s+/).filter(Boolean);
|
|
840
850
|
const visible = visibleTools();
|
|
841
|
-
const available = PLUNE_TOOLS.filter((t) => !visible.includes(t.name) && !(scope === "read" && t.write)).filter((t) => words.every((w) => `${t.name} ${t.title} ${t.description}`.toLowerCase().includes(w))).map((t) => ({
|
|
842
|
-
|
|
851
|
+
const available = PLUNE_TOOLS.filter((t) => !visible.includes(t.name) && !(scope === "read" && t.write)).filter((t) => words.every((w) => `${t.name} ${t.title} ${t.description}`.toLowerCase().includes(w))).map((t) => ({
|
|
852
|
+
name: t.name,
|
|
853
|
+
title: t.title,
|
|
854
|
+
description: t.description,
|
|
855
|
+
write: t.write,
|
|
856
|
+
...fixed ? { inputSchema: z3.toJSONSchema(t.input, { target: "draft-2020-12", io: "input" }) } : {}
|
|
857
|
+
}));
|
|
858
|
+
return { revealed: fixed ? [] : names, available, visible };
|
|
843
859
|
},
|
|
844
860
|
async plune_cases_update(i) {
|
|
845
861
|
const cases = i["cases"];
|
package/dist/reporter-core.cjs
CHANGED
|
@@ -485,7 +485,7 @@ function cutErrorContext(attempt, home) {
|
|
|
485
485
|
const text = attempt.errors.map((e) => e.text).filter((t) => t !== "").join("\n\n");
|
|
486
486
|
return cut(machineless(text, attempt.repoRoot, home));
|
|
487
487
|
}
|
|
488
|
-
var printable = (text) => text.replace(/[\u0000-\u001f\u007f-\u009f]/g, "?");
|
|
488
|
+
var printable = (text) => text.replace(/[\u0000-\u001f\u007f-\u009f\u2028\u2029\u202a-\u202e\u2066-\u2069]/g, "?");
|
|
489
489
|
var mediaTypeOf = (contentType) => contentType?.split(";")[0]?.trim().toLowerCase() || void 0;
|
|
490
490
|
var TEXT_TYPES = /* @__PURE__ */ new Set(["application/json", "text/plain"]);
|
|
491
491
|
var isTextType = (contentType) => TEXT_TYPES.has(mediaTypeOf(contentType) ?? "");
|
package/dist/reporter-core.js
CHANGED
|
@@ -435,7 +435,7 @@ function cutErrorContext(attempt, home) {
|
|
|
435
435
|
const text = attempt.errors.map((e) => e.text).filter((t) => t !== "").join("\n\n");
|
|
436
436
|
return cut(machineless(text, attempt.repoRoot, home));
|
|
437
437
|
}
|
|
438
|
-
var printable = (text) => text.replace(/[\u0000-\u001f\u007f-\u009f]/g, "?");
|
|
438
|
+
var printable = (text) => text.replace(/[\u0000-\u001f\u007f-\u009f\u2028\u2029\u202a-\u202e\u2066-\u2069]/g, "?");
|
|
439
439
|
var mediaTypeOf = (contentType) => contentType?.split(";")[0]?.trim().toLowerCase() || void 0;
|
|
440
440
|
var TEXT_TYPES = /* @__PURE__ */ new Set(["application/json", "text/plain"]);
|
|
441
441
|
var isTextType = (contentType) => TEXT_TYPES.has(mediaTypeOf(contentType) ?? "");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plune-ai/cli",
|
|
3
|
-
"version": "0.34.
|
|
3
|
+
"version": "0.34.6",
|
|
4
4
|
"description": "AI-powered assertion testing for LLM apps — write assertions, run them against any provider, get a pass/fail report (local, CI, or diff).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -43,7 +43,8 @@
|
|
|
43
43
|
"files": [
|
|
44
44
|
"dist",
|
|
45
45
|
"README.md",
|
|
46
|
-
"LICENSE"
|
|
46
|
+
"LICENSE",
|
|
47
|
+
"THIRD_PARTY_NOTICES"
|
|
47
48
|
],
|
|
48
49
|
"engines": {
|
|
49
50
|
"node": ">=20.0.0"
|
|
@@ -68,7 +69,8 @@
|
|
|
68
69
|
"dependencies": {
|
|
69
70
|
"@anthropic-ai/sdk": "^0.102.0",
|
|
70
71
|
"@clack/prompts": "^1.5.1",
|
|
71
|
-
"@modelcontextprotocol/
|
|
72
|
+
"@modelcontextprotocol/client": "2.4.0",
|
|
73
|
+
"@modelcontextprotocol/server": "2.4.0",
|
|
72
74
|
"ajv": "^8.17.1",
|
|
73
75
|
"commander": "^12.0.0",
|
|
74
76
|
"dotenv": "^16.4.0",
|
|
@@ -81,6 +83,7 @@
|
|
|
81
83
|
},
|
|
82
84
|
"devDependencies": {
|
|
83
85
|
"@huggingface/transformers": "4.2.0",
|
|
86
|
+
"@modelcontextprotocol/sdk": "1.32.2",
|
|
84
87
|
"@types/better-sqlite3": "^7.6.13",
|
|
85
88
|
"@types/node": "^25.9.1",
|
|
86
89
|
"@typescript-eslint/eslint-plugin": "^8.0.0",
|