katt 0.0.8 → 0.0.10

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/dist/katt.js CHANGED
@@ -1,7 +1,9 @@
1
1
  #!/usr/bin/env node
2
- import { u as r } from "./runCli-425rgVp8.js";
3
- r().then((e) => {
4
- process.exit(e);
2
+ import { t as e } from "./runCli-DkkiL_uk.js";
3
+ //#region src/cli.ts
4
+ e().then((e) => {
5
+ process.exit(e);
5
6
  }).catch((e) => {
6
- console.error(`Unexpected error: ${String(e)}`), process.exit(1);
7
+ console.error(`Unexpected error: ${String(e)}`), process.exit(1);
7
8
  });
9
+ //#endregion
@@ -0,0 +1,388 @@
1
+ import { fileURLToPath as e, pathToFileURL as t } from "node:url";
2
+ import { readFile as n, readdir as r } from "node:fs/promises";
3
+ import { dirname as i, matchesGlob as a, resolve as o } from "node:path";
4
+ import { AsyncLocalStorage as s } from "node:async_hooks";
5
+ import { readFileSync as c } from "node:fs";
6
+ //#region src/cli/findEvalFiles.ts
7
+ var l = /\.eval\.(js|ts)$/, u = new Set([".git", "node_modules"]);
8
+ function d(e, t) {
9
+ return t.some((t) => e === t || a(e, t));
10
+ }
11
+ async function f(e, t = []) {
12
+ let n = await r(e, { withFileTypes: !0 }), i = [];
13
+ return await Promise.all(n.map(async (n) => {
14
+ let r = o(e, n.name);
15
+ if (n.isDirectory()) {
16
+ if (u.has(n.name) || d(r, t)) return;
17
+ i.push(...await f(r, t));
18
+ return;
19
+ }
20
+ n.isFile() && l.test(n.name) && !d(r, t) && i.push(r);
21
+ })), i;
22
+ }
23
+ //#endregion
24
+ //#region src/lib/context/context.ts
25
+ var p = new s(), ee = {
26
+ describeStack: [],
27
+ itStack: [],
28
+ tokenUsageStack: [],
29
+ modelStack: []
30
+ }, m = 0, h = 0, g = [], _ = [], v = 0;
31
+ function y() {
32
+ return p.getStore() ?? ee;
33
+ }
34
+ function b(e) {
35
+ return {
36
+ describeStack: [...e.describeStack],
37
+ itStack: [...e.itStack],
38
+ tokenUsageStack: [...e.tokenUsageStack],
39
+ modelStack: [...e.modelStack]
40
+ };
41
+ }
42
+ function te() {
43
+ return m += 1, `d${m}`;
44
+ }
45
+ function x() {
46
+ return h += 1, `i${h}`;
47
+ }
48
+ function S(e, t) {
49
+ let n = t ?? b(y());
50
+ return p.run(n, e);
51
+ }
52
+ function C() {
53
+ return b(y());
54
+ }
55
+ function ne(e) {
56
+ y().describeStack.push({
57
+ id: te(),
58
+ description: e
59
+ });
60
+ }
61
+ function w() {
62
+ y().describeStack.pop();
63
+ }
64
+ function T() {
65
+ return y().describeStack.map((e) => e.description).join(" > ");
66
+ }
67
+ function E() {
68
+ return [...y().describeStack];
69
+ }
70
+ function D(e) {
71
+ y().itStack.push({
72
+ id: x(),
73
+ description: e
74
+ }), y().tokenUsageStack.push(0), y().modelStack.push(void 0);
75
+ }
76
+ function O() {
77
+ y().itStack.pop(), y().tokenUsageStack.pop(), y().modelStack.pop();
78
+ }
79
+ function k() {
80
+ return y().itStack.map((e) => e.description).join(" > ");
81
+ }
82
+ function re() {
83
+ return [...y().itStack];
84
+ }
85
+ function ie(e) {
86
+ if (!Number.isFinite(e) || e <= 0) return;
87
+ let t = y(), n = t.tokenUsageStack.length - 1;
88
+ n < 0 || (t.tokenUsageStack[n] += e);
89
+ }
90
+ function ae() {
91
+ let e = y(), t = e.tokenUsageStack.length - 1;
92
+ return t < 0 ? 0 : e.tokenUsageStack[t] ?? 0;
93
+ }
94
+ function oe(e) {
95
+ if (e.length === 0) return;
96
+ let t = y(), n = t.modelStack.length - 1;
97
+ n < 0 || (t.modelStack[n] = e);
98
+ }
99
+ function se() {
100
+ let e = y(), t = e.modelStack.length - 1;
101
+ if (!(t < 0)) return e.modelStack[t];
102
+ }
103
+ function A(e) {
104
+ g.push(e);
105
+ }
106
+ function ce() {
107
+ v += 1;
108
+ }
109
+ function le() {
110
+ return v;
111
+ }
112
+ function ue() {
113
+ v = 0;
114
+ }
115
+ function de(e) {
116
+ _.push(e);
117
+ }
118
+ function fe() {
119
+ return [..._];
120
+ }
121
+ function pe() {
122
+ _.length = 0;
123
+ }
124
+ async function me() {
125
+ let e = [];
126
+ for (; g.length > 0;) {
127
+ let t = g.splice(0, g.length), n = await Promise.allSettled(t);
128
+ e.push(...n);
129
+ }
130
+ return e;
131
+ }
132
+ //#endregion
133
+ //#region src/lib/output/color.ts
134
+ var j = "\x1B[1;36m", M = "\x1B[33m", N = "\x1B[38;5;208m", P = "\x1B[1;38;5;208m", F = "\x1B[0m";
135
+ function I(e) {
136
+ return `${j}${e}${F}`;
137
+ }
138
+ function L(e) {
139
+ return `${M}${e}${F}`;
140
+ }
141
+ function R(e) {
142
+ return `${N}${e}${F}`;
143
+ }
144
+ function z(e) {
145
+ return `${P}${e}${F}`;
146
+ }
147
+ //#endregion
148
+ //#region src/lib/output/testLogging.ts
149
+ var B = "";
150
+ function he() {
151
+ B = "";
152
+ }
153
+ function ge({ suitePath: e, casePath: t, durationMs: n, model: r, tokenUsage: i }) {
154
+ let a = e.length > 0 ? e : "(root)", o = t.length > 0 ? t : "(root)";
155
+ B !== a && (console.log(`Suite "${I(a)}"`), B = a);
156
+ let s = [`Test "${I(o)}"`, `- Finished in ${I(`${n} ms`)}`];
157
+ r && s.push(`- Model ${I(r)}`), (i ?? 0) > 0 && s.push(`- Tokens used ${I(String(i))}`), s.push("---"), console.log(s.join("\n"));
158
+ }
159
+ function V(e, t = "(root)") {
160
+ let n = k();
161
+ ge({
162
+ suitePath: T(),
163
+ casePath: n.length > 0 ? n : t,
164
+ durationMs: e,
165
+ model: se(),
166
+ tokenUsage: ae()
167
+ });
168
+ }
169
+ //#endregion
170
+ //#region src/lib/it/it.ts
171
+ function _e(e, t) {
172
+ S(() => {
173
+ ce(), D(e);
174
+ let n = Date.now(), r = () => Date.now() - n;
175
+ try {
176
+ let e = t();
177
+ if (e && typeof e.then == "function") {
178
+ A(e.then(() => {
179
+ V(r());
180
+ }).catch((e) => {
181
+ throw V(r()), e;
182
+ }).finally(() => {
183
+ O();
184
+ }));
185
+ return;
186
+ }
187
+ } catch (e) {
188
+ throw V(r()), O(), e;
189
+ }
190
+ V(r()), O();
191
+ }, C());
192
+ }
193
+ //#endregion
194
+ //#region src/lib/context/evalFileContext.ts
195
+ var H = new s(), U = new URL("data:application/json;base64,ewogICJuYW1lIjogImthdHQiLAogICJ2ZXJzaW9uIjogIjAuMC4xMCIsCiAgImRlc2NyaXB0aW9uIjogIkNMSSB0b29sIHRoYXQgdGVzdHMgdGhlIG91dHB1dCBvZiBhZ2VudGljIEFJIHRvb2xzIiwKICAia2V5d29yZHMiOiBbCiAgICAiY2xpIiwKICAgICJhaSIsCiAgICAiYWdlbnRpYy1haSIsCiAgICAidGVzdGluZyIsCiAgICAiZXZhbHVhdGlvbiIKICBdLAogICJhdXRob3IiOiAiUmFwaGFlbCBQb3J0byAoaHR0cHM6Ly9naXRodWIuY29tL3JhcGhhZWxwb3IpIiwKICAibGljZW5zZSI6ICJNSVQiLAogICJ0eXBlIjogIm1vZHVsZSIsCiAgIm1haW4iOiAiZGlzdC9pbmRleC5qcyIsCiAgImV4cG9ydHMiOiB7CiAgICAiLiI6IHsKICAgICAgInR5cGVzIjogIi4vZGlzdC9pbmRleC5kLnRzIiwKICAgICAgImltcG9ydCI6ICIuL2Rpc3QvaW5kZXguanMiCiAgICB9CiAgfSwKICAiYmluIjogewogICAgImthdHQiOiAiZGlzdC9rYXR0LmpzIgogIH0sCiAgInNjcmlwdHMiOiB7CiAgICAiYnVpbGQiOiAidml0ZSBidWlsZCIsCiAgICAiZGV2IjogInRzeCBzcmMvaW5kZXgudHMiLAogICAgImxpbnQiOiAiYmlvbWUgbGludCAuL3NyYyIsCiAgICAiZm9ybWF0IjogImJpb21lIGZvcm1hdCAtLXdyaXRlIC4vc3JjIiwKICAgICJ0ZXN0IjogInZpdGVzdCIsCiAgICAidHlwZWNoZWNrIjogInRzYyAtcCB0c2NvbmZpZy5qc29uIC0tbm9FbWl0IiwKICAgICJ0ZXN0OmJ1aWxkIjogIm5vZGUgLi9kaXN0L2thdHQuanMiLAogICAgInRlc3Q6YnVpbGQ6Y29kZXgiOiAibm9kZSAuL2Rpc3Qva2F0dC5qcyAtLWNvbmZpZy1maWxlPS4va2F0dC1jb2RleC5qc29uIgogIH0sCiAgInR5cGVzIjogImRpc3QvaW5kZXguZC50cyIsCiAgImRldkRlcGVuZGVuY2llcyI6IHsKICAgICJAYmlvbWVqcy9iaW9tZSI6ICIyLjQuOCIsCiAgICAiQHR5cGVzL25vZGUiOiAiMjUuNS4wIiwKICAgICJ0c3giOiAiNC4yMS4wIiwKICAgICJ0eXBlc2NyaXB0IjogIjYuMC4yIiwKICAgICJ2aXRlIjogIjguMC4yIiwKICAgICJ2aXRlLXBsdWdpbi1kdHMiOiAiNC41LjQiLAogICAgInZpdGVzdCI6ICI0LjEuMSIsCiAgICAidnNjb2RlLWpzb25ycGMiOiAiXjguMi4xIgogIH0sCiAgImRlcGVuZGVuY2llcyI6IHsKICAgICJAZ2l0aHViL2NvcGlsb3Qtc2RrIjogIjAuMi4wIgogIH0sCiAgImJ1Z3MiOiB7CiAgICAidXJsIjogImh0dHBzOi8vZ2l0aHViLmNvbS9yYXBoYWVscG9yL2thdHQvaXNzdWVzIgogIH0sCiAgImhvbWVwYWdlIjogImh0dHBzOi8vZ2l0aHViLmNvbS9yYXBoYWVscG9yL2thdHQiCn0K", "" + import.meta.url), W;
196
+ function ve() {
197
+ if (W !== void 0) return W;
198
+ try {
199
+ let t = U.protocol === "data:" ? ye(U) : c(e(U), "utf8"), n = JSON.parse(t);
200
+ W = typeof n.version == "string" ? n.version : "unknown";
201
+ } catch {
202
+ W = "unknown";
203
+ }
204
+ return W;
205
+ }
206
+ function ye(e) {
207
+ let t = e.pathname.indexOf(",");
208
+ if (t < 0) throw Error("Invalid data URL.");
209
+ let n = e.pathname.slice(0, t), r = e.pathname.slice(t + 1);
210
+ return n.includes(";base64") ? Buffer.from(r, "base64").toString("utf8") : decodeURIComponent(r);
211
+ }
212
+ //#endregion
213
+ //#region src/cli/banner.ts
214
+ function G() {
215
+ let e = `v${ve()}`, t = Math.max(0, Math.floor((35 - e.length) / 2)), n = `${" ".repeat(t)}${e}`;
216
+ console.log(`
217
+ ${L(" ██╗ ██╗ █████╗ ████████╗████████╗")}
218
+ ${L(" ██║ ██╔╝██╔══██╗╚══██╔══╝╚══██╔══╝")}
219
+ ${L(" █████╔╝ ███████║ ██║ ██║")}
220
+ ${R(" ██╔═██╗ ██╔══██║ ██║ ██║")}
221
+ ${R(" ██║ ██╗██║ ██║ ██║ ██║")}
222
+ ${z(" ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝")}
223
+ ${L(n)}
224
+ `);
225
+ }
226
+ //#endregion
227
+ //#region src/lib/expect/snapshotConfig.ts
228
+ var K = !1;
229
+ function be(e) {
230
+ K = e;
231
+ }
232
+ function xe() {
233
+ return K;
234
+ }
235
+ //#endregion
236
+ //#region src/lib/config/config.ts
237
+ var Se = "gh-copilot", q = "katt.json", J;
238
+ function Y() {
239
+ return typeof J == "string" && J.length > 0 ? {
240
+ resolvedPath: o(process.cwd(), J),
241
+ label: J
242
+ } : {
243
+ resolvedPath: o(process.cwd(), q),
244
+ label: q
245
+ };
246
+ }
247
+ function X(e) {
248
+ J = e;
249
+ }
250
+ function Ce(e, t) {
251
+ return typeof e == "object" && !!e && "code" in e && e.code === t;
252
+ }
253
+ function we(e, t) {
254
+ try {
255
+ let t = JSON.parse(e);
256
+ return typeof t == "object" && t ? t : void 0;
257
+ } catch (e) {
258
+ console.warn(`Failed to parse ${t}: ${String(e)}`);
259
+ return;
260
+ }
261
+ }
262
+ function Te(e, t) {
263
+ e && "copilot" in e && console.warn(`Deprecated config property "copilot" found in ${t}. Use "agent" and "agentOptions" instead.`);
264
+ }
265
+ async function Z() {
266
+ let { resolvedPath: e, label: t } = Y();
267
+ try {
268
+ let r = we(await n(e, "utf8"), t);
269
+ return Te(r, t), r;
270
+ } catch (e) {
271
+ if (Ce(e, "ENOENT")) return;
272
+ console.warn(`Failed to read ${t}: ${String(e)}`);
273
+ return;
274
+ }
275
+ }
276
+ function Q(e) {
277
+ if (e === "gh-copilot" || e === "codex") return e;
278
+ }
279
+ function Ee(e, t) {
280
+ if (!e || Q(e?.agent) !== t) return;
281
+ let n = e.agentOptions;
282
+ if (typeof n != "object" || !n || Array.isArray(n)) return;
283
+ let r = { ...n }, i = r.model;
284
+ return (typeof i != "string" || i.length === 0) && delete r.model, Object.keys(r).length > 0 ? r : void 0;
285
+ }
286
+ function De(e) {
287
+ if (!(typeof e != "number" || !Number.isFinite(e)) && !(e <= 0)) return Math.floor(e);
288
+ }
289
+ function Oe(e) {
290
+ let t = e?.prompt;
291
+ if (!(typeof t != "object" || !t || Array.isArray(t))) return De(t.timeoutMs);
292
+ }
293
+ function ke(e) {
294
+ if (!e || !Array.isArray(e.ignorePatterns)) return [];
295
+ let t = i(Y().resolvedPath);
296
+ return e.ignorePatterns.filter((e) => typeof e == "string" && e.length > 0).map((e) => o(t, e));
297
+ }
298
+ async function Ae() {
299
+ let e = await Z(), t = Q(e?.agent) ?? Se;
300
+ return {
301
+ agent: t,
302
+ agentOptions: Ee(e, t),
303
+ promptTimeoutMs: Oe(e)
304
+ };
305
+ }
306
+ async function $() {
307
+ return ke(await Z());
308
+ }
309
+ //#endregion
310
+ //#region src/cli/runCli.ts
311
+ function je(e) {
312
+ return `${String(e.getHours()).padStart(2, "0")}:${String(e.getMinutes()).padStart(2, "0")}:${String(e.getSeconds()).padStart(2, "0")}`;
313
+ }
314
+ function Me() {
315
+ console.log([
316
+ "Usage:",
317
+ " katt [options]",
318
+ "",
319
+ "Options:",
320
+ " -h, --help Show CLI usage information",
321
+ " -u, --update-snapshots Update snapshot files on mismatch",
322
+ " --config-file PATH Use a custom config file instead of katt.json"
323
+ ].join("\n"));
324
+ }
325
+ function Ne(e) {
326
+ let t;
327
+ for (let n = 0; n < e.length; n += 1) {
328
+ let r = e[n];
329
+ if (r === "--config-file") {
330
+ let r = e[n + 1];
331
+ if (r === void 0 || r.length === 0) return { error: "Missing value for --config-file." };
332
+ t = r, n += 1;
333
+ continue;
334
+ }
335
+ if (r.startsWith("--config-file=")) {
336
+ let e = r.slice(14);
337
+ if (e.length === 0) return { error: "Missing value for --config-file." };
338
+ t = e;
339
+ }
340
+ }
341
+ return { configFilePath: t };
342
+ }
343
+ async function Pe() {
344
+ let e = process.argv.slice(2);
345
+ if (X(void 0), e.includes("--help") || e.includes("-h")) return G(), Me(), 0;
346
+ let n = Ne(e);
347
+ if (n.error) return G(), console.error(n.error), 1;
348
+ X(n.configFilePath), be(e.includes("--update-snapshots") || e.includes("-u")), G();
349
+ let r = /* @__PURE__ */ new Date();
350
+ he(), pe(), ue();
351
+ let i = await $(), a = await f(process.cwd(), i);
352
+ if (a.length === 0) return console.log("No .eval.js or .eval.ts files found."), 1;
353
+ let o = (await Promise.allSettled(a.map((e) => H.run({ evalFile: e }, () => import(t(e).href))))).map((e, t) => ({
354
+ result: e,
355
+ file: a[t]
356
+ })).filter(({ result: e }) => e.status === "rejected");
357
+ if (o.length > 0) {
358
+ for (let e of o) {
359
+ let t = e.result.status === "rejected" ? e.result.reason : void 0;
360
+ console.error(`Error executing ${e.file}: ${String(t)}`);
361
+ }
362
+ return 1;
363
+ }
364
+ let s = (await me()).filter((e) => e.status === "rejected");
365
+ if (s.length > 0) {
366
+ for (let e of s) e.status === "rejected" && console.error(`Error executing async test: ${String(e.reason)}`);
367
+ return 1;
368
+ }
369
+ let c = fe();
370
+ if (c.length > 0) {
371
+ console.error("❌ Failed tests:");
372
+ for (let [e, t] of c.entries()) {
373
+ let n = [t.describePath, t.itPath].filter((e) => e.length > 0).join(" > "), r = n.length > 0 ? `${n}: ` : "";
374
+ console.error(`${e + 1}. ${r}${t.message}`);
375
+ }
376
+ return 1;
377
+ }
378
+ let l = le(), u = Date.now() - r.getTime();
379
+ return console.log([
380
+ "---",
381
+ `Files ${I(`${a.length} passed`)}`,
382
+ `Evals ${I(`${l} passed`)}`,
383
+ `Start at ${I(je(r))}`,
384
+ `Duration ${I(`${u}ms`)}`
385
+ ].join("\n")), 0;
386
+ }
387
+ //#endregion
388
+ export { S as _, _e as a, C as c, re as d, k as f, A as g, de as h, H as i, E as l, ne as m, Ae as n, V as o, w as p, xe as r, ie as s, Pe as t, T as u, oe as v };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "katt",
3
- "version": "0.0.8",
3
+ "version": "0.0.10",
4
4
  "description": "CLI tool that tests the output of agentic AI tools",
5
5
  "keywords": [
6
6
  "cli",
@@ -34,17 +34,17 @@
34
34
  },
35
35
  "types": "dist/index.d.ts",
36
36
  "devDependencies": {
37
- "@biomejs/biome": "2.4.2",
38
- "@types/node": "25.2.3",
37
+ "@biomejs/biome": "2.4.8",
38
+ "@types/node": "25.5.0",
39
39
  "tsx": "4.21.0",
40
- "typescript": "5.9.3",
41
- "vite": "7.3.1",
40
+ "typescript": "6.0.2",
41
+ "vite": "8.0.2",
42
42
  "vite-plugin-dts": "4.5.4",
43
- "vitest": "4.0.18",
43
+ "vitest": "4.1.1",
44
44
  "vscode-jsonrpc": "^8.2.1"
45
45
  },
46
46
  "dependencies": {
47
- "@github/copilot-sdk": "0.1.23"
47
+ "@github/copilot-sdk": "0.2.0"
48
48
  },
49
49
  "bugs": {
50
50
  "url": "https://github.com/raphaelpor/katt/issues"
@@ -1 +0,0 @@
1
- heeey
@@ -1 +0,0 @@
1
- heeey