katt 0.0.9 → 0.0.11

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-j5xhVCdB.js";
3
- r().then((e) => {
4
- process.exit(e);
2
+ import { t as e } from "./runCli-CJ7_lGMV.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,398 @@
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 he = "\x1B[1;36m", j = "\x1B[33m", M = "\x1B[38;5;208m", N = "\x1B[1;38;5;208m", P = "\x1B[0m";
135
+ function F(e) {
136
+ return `${he}${e}${P}`;
137
+ }
138
+ function I(e) {
139
+ return `${j}${e}${P}`;
140
+ }
141
+ function L(e) {
142
+ return `${M}${e}${P}`;
143
+ }
144
+ function R(e) {
145
+ return `${N}${e}${P}`;
146
+ }
147
+ //#endregion
148
+ //#region src/lib/output/testLogging.ts
149
+ var z = "";
150
+ function ge() {
151
+ z = "";
152
+ }
153
+ function _e({ 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
+ z !== a && (console.log(`Suite "${F(a)}"`), z = a);
156
+ let s = [`Test "${F(o)}"`, `- Finished in ${F(`${n} ms`)}`];
157
+ r && s.push(`- Model ${F(r)}`), (i ?? 0) > 0 && s.push(`- Tokens used ${F(String(i))}`), s.push("---"), console.log(s.join("\n"));
158
+ }
159
+ function B(e, t = "(root)") {
160
+ let n = k();
161
+ _e({
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 ve(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
+ B(r());
180
+ }).catch((e) => {
181
+ throw B(r()), e;
182
+ }).finally(() => {
183
+ O();
184
+ }));
185
+ return;
186
+ }
187
+ } catch (e) {
188
+ throw B(r()), O(), e;
189
+ }
190
+ B(r()), O();
191
+ }, C());
192
+ }
193
+ //#endregion
194
+ //#region src/lib/context/evalFileContext.ts
195
+ var V = new s(), H = new URL("data:application/json;base64,ewogICJuYW1lIjogImthdHQiLAogICJ2ZXJzaW9uIjogIjAuMC4xMSIsCiAgImRlc2NyaXB0aW9uIjogIkNMSSB0b29sIHRoYXQgdGVzdHMgdGhlIG91dHB1dCBvZiBhZ2VudGljIEFJIHRvb2xzIiwKICAia2V5d29yZHMiOiBbCiAgICAiY2xpIiwKICAgICJhaSIsCiAgICAiYWdlbnRpYy1haSIsCiAgICAidGVzdGluZyIsCiAgICAiZXZhbHVhdGlvbiIKICBdLAogICJhdXRob3IiOiAiUmFwaGFlbCBQb3J0byAoaHR0cHM6Ly9naXRodWIuY29tL3JhcGhhZWxwb3IpIiwKICAibGljZW5zZSI6ICJNSVQiLAogICJ0eXBlIjogIm1vZHVsZSIsCiAgIm1haW4iOiAiZGlzdC9pbmRleC5qcyIsCiAgImV4cG9ydHMiOiB7CiAgICAiLiI6IHsKICAgICAgInR5cGVzIjogIi4vZGlzdC9pbmRleC5kLnRzIiwKICAgICAgImltcG9ydCI6ICIuL2Rpc3QvaW5kZXguanMiCiAgICB9CiAgfSwKICAiYmluIjogewogICAgImthdHQiOiAiZGlzdC9rYXR0LmpzIgogIH0sCiAgInNjcmlwdHMiOiB7CiAgICAiYnVpbGQiOiAidml0ZSBidWlsZCIsCiAgICAiZGV2IjogInRzeCBzcmMvaW5kZXgudHMiLAogICAgImxpbnQiOiAiYmlvbWUgbGludCAuL3NyYyIsCiAgICAiZm9ybWF0IjogImJpb21lIGZvcm1hdCAtLXdyaXRlIC4vc3JjIiwKICAgICJ0ZXN0IjogInZpdGVzdCIsCiAgICAidHlwZWNoZWNrIjogInRzYyAtcCB0c2NvbmZpZy5qc29uIC0tbm9FbWl0IiwKICAgICJ0ZXN0OmJ1aWxkIjogIm5vZGUgLi9kaXN0L2thdHQuanMiLAogICAgInRlc3Q6YnVpbGQ6Y29kZXgiOiAibm9kZSAuL2Rpc3Qva2F0dC5qcyAtLWNvbmZpZy1maWxlPS4va2F0dC1jb2RleC5qc29uIgogIH0sCiAgInR5cGVzIjogImRpc3QvaW5kZXguZC50cyIsCiAgImRldkRlcGVuZGVuY2llcyI6IHsKICAgICJAYmlvbWVqcy9iaW9tZSI6ICIyLjQuMTAiLAogICAgIkB0eXBlcy9ub2RlIjogIjI1LjUuMiIsCiAgICAidHN4IjogIjQuMjEuMCIsCiAgICAidHlwZXNjcmlwdCI6ICI2LjAuMiIsCiAgICAidml0ZSI6ICI4LjAuMyIsCiAgICAidml0ZS1wbHVnaW4tZHRzIjogIjQuNS40IiwKICAgICJ2aXRlc3QiOiAiNC4xLjIiLAogICAgInZzY29kZS1qc29ucnBjIjogIl44LjIuMSIKICB9LAogICJkZXBlbmRlbmNpZXMiOiB7CiAgICAiQGdpdGh1Yi9jb3BpbG90LXNkayI6ICIwLjIuMCIKICB9LAogICJidWdzIjogewogICAgInVybCI6ICJodHRwczovL2dpdGh1Yi5jb20vcmFwaGFlbHBvci9rYXR0L2lzc3VlcyIKICB9LAogICJob21lcGFnZSI6ICJodHRwczovL2dpdGh1Yi5jb20vcmFwaGFlbHBvci9rYXR0Igp9Cg==", "" + import.meta.url), U;
196
+ function ye() {
197
+ if (U !== void 0) return U;
198
+ try {
199
+ let t = H.protocol === "data:" ? be(H) : c(e(H), "utf8"), n = JSON.parse(t);
200
+ U = typeof n.version == "string" ? n.version : "unknown";
201
+ } catch {
202
+ U = "unknown";
203
+ }
204
+ return U;
205
+ }
206
+ function be(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 W() {
215
+ let e = `v${ye()}`, t = Math.max(0, Math.floor((35 - e.length) / 2)), n = `${" ".repeat(t)}${e}`;
216
+ console.log(`
217
+ ${I(" ██╗ ██╗ █████╗ ████████╗████████╗")}
218
+ ${I(" ██║ ██╔╝██╔══██╗╚══██╔══╝╚══██╔══╝")}
219
+ ${I(" █████╔╝ ███████║ ██║ ██║")}
220
+ ${L(" ██╔═██╗ ██╔══██║ ██║ ██║")}
221
+ ${L(" ██║ ██╗██║ ██║ ██║ ██║")}
222
+ ${R(" ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝")}
223
+ ${I(n)}
224
+ `);
225
+ }
226
+ //#endregion
227
+ //#region src/lib/expect/snapshotConfig.ts
228
+ var G = !1;
229
+ function xe(e) {
230
+ G = e;
231
+ }
232
+ function Se() {
233
+ return G;
234
+ }
235
+ //#endregion
236
+ //#region src/lib/prompt/reasoningConfig.ts
237
+ var K = !1;
238
+ function Ce(e) {
239
+ K = e;
240
+ }
241
+ function we() {
242
+ return K;
243
+ }
244
+ //#endregion
245
+ //#region src/lib/config/config.ts
246
+ var Te = "gh-copilot", q = "katt.json", J;
247
+ function Y() {
248
+ return typeof J == "string" && J.length > 0 ? {
249
+ resolvedPath: o(process.cwd(), J),
250
+ label: J
251
+ } : {
252
+ resolvedPath: o(process.cwd(), q),
253
+ label: q
254
+ };
255
+ }
256
+ function X(e) {
257
+ J = e;
258
+ }
259
+ function Ee(e, t) {
260
+ return typeof e == "object" && !!e && "code" in e && e.code === t;
261
+ }
262
+ function De(e, t) {
263
+ try {
264
+ let t = JSON.parse(e);
265
+ return typeof t == "object" && t ? t : void 0;
266
+ } catch (e) {
267
+ console.warn(`Failed to parse ${t}: ${String(e)}`);
268
+ return;
269
+ }
270
+ }
271
+ function Oe(e, t) {
272
+ e && "copilot" in e && console.warn(`Deprecated config property "copilot" found in ${t}. Use "agent" and "agentOptions" instead.`);
273
+ }
274
+ async function Z() {
275
+ let { resolvedPath: e, label: t } = Y();
276
+ try {
277
+ let r = De(await n(e, "utf8"), t);
278
+ return Oe(r, t), r;
279
+ } catch (e) {
280
+ if (Ee(e, "ENOENT")) return;
281
+ console.warn(`Failed to read ${t}: ${String(e)}`);
282
+ return;
283
+ }
284
+ }
285
+ function Q(e) {
286
+ if (e === "gh-copilot" || e === "codex") return e;
287
+ }
288
+ function ke(e, t) {
289
+ if (!e || Q(e?.agent) !== t) return;
290
+ let n = e.agentOptions;
291
+ if (typeof n != "object" || !n || Array.isArray(n)) return;
292
+ let r = { ...n }, i = r.model;
293
+ return (typeof i != "string" || i.length === 0) && delete r.model, Object.keys(r).length > 0 ? r : void 0;
294
+ }
295
+ function Ae(e) {
296
+ if (!(typeof e != "number" || !Number.isFinite(e)) && !(e <= 0)) return Math.floor(e);
297
+ }
298
+ function $(e) {
299
+ let t = e?.prompt;
300
+ if (!(typeof t != "object" || !t || Array.isArray(t))) return Ae(t.timeoutMs);
301
+ }
302
+ function je(e) {
303
+ if (!e || !Array.isArray(e.ignorePatterns)) return [];
304
+ let t = i(Y().resolvedPath);
305
+ return e.ignorePatterns.filter((e) => typeof e == "string" && e.length > 0).map((e) => o(t, e));
306
+ }
307
+ async function Me() {
308
+ let e = await Z(), t = Q(e?.agent) ?? Te;
309
+ return {
310
+ agent: t,
311
+ agentOptions: ke(e, t),
312
+ promptTimeoutMs: $(e)
313
+ };
314
+ }
315
+ async function Ne() {
316
+ return je(await Z());
317
+ }
318
+ //#endregion
319
+ //#region src/cli/runCli.ts
320
+ function Pe(e) {
321
+ return `${String(e.getHours()).padStart(2, "0")}:${String(e.getMinutes()).padStart(2, "0")}:${String(e.getSeconds()).padStart(2, "0")}`;
322
+ }
323
+ function Fe() {
324
+ console.log([
325
+ "Usage:",
326
+ " katt [options]",
327
+ "",
328
+ "Options:",
329
+ " -h, --help Show CLI usage information",
330
+ " -u, --update-snapshots Update snapshot files on mismatch",
331
+ " --save-reasoning Save runtime reasoning to per-prompt files",
332
+ " --config-file PATH Use a custom config file instead of katt.json"
333
+ ].join("\n"));
334
+ }
335
+ function Ie(e) {
336
+ let t;
337
+ for (let n = 0; n < e.length; n += 1) {
338
+ let r = e[n];
339
+ if (r === "--config-file") {
340
+ let r = e[n + 1];
341
+ if (r === void 0 || r.length === 0) return { error: "Missing value for --config-file." };
342
+ t = r, n += 1;
343
+ continue;
344
+ }
345
+ if (r.startsWith("--config-file=")) {
346
+ let e = r.slice(14);
347
+ if (e.length === 0) return { error: "Missing value for --config-file." };
348
+ t = e;
349
+ }
350
+ }
351
+ return { configFilePath: t };
352
+ }
353
+ async function Le() {
354
+ let e = process.argv.slice(2);
355
+ if (X(void 0), e.includes("--help") || e.includes("-h")) return W(), Fe(), 0;
356
+ let n = Ie(e);
357
+ if (n.error) return W(), console.error(n.error), 1;
358
+ X(n.configFilePath), xe(e.includes("--update-snapshots") || e.includes("-u")), Ce(e.includes("--save-reasoning")), W();
359
+ let r = /* @__PURE__ */ new Date();
360
+ ge(), pe(), ue();
361
+ let i = await Ne(), a = await f(process.cwd(), i);
362
+ if (a.length === 0) return console.log("No .eval.js or .eval.ts files found."), 1;
363
+ let o = (await Promise.allSettled(a.map((e) => V.run({ evalFile: e }, () => import(t(e).href))))).map((e, t) => ({
364
+ result: e,
365
+ file: a[t]
366
+ })).filter(({ result: e }) => e.status === "rejected");
367
+ if (o.length > 0) {
368
+ for (let e of o) {
369
+ let t = e.result.status === "rejected" ? e.result.reason : void 0;
370
+ console.error(`Error executing ${e.file}: ${String(t)}`);
371
+ }
372
+ return 1;
373
+ }
374
+ let s = (await me()).filter((e) => e.status === "rejected");
375
+ if (s.length > 0) {
376
+ for (let e of s) e.status === "rejected" && console.error(`Error executing async test: ${String(e.reason)}`);
377
+ return 1;
378
+ }
379
+ let c = fe();
380
+ if (c.length > 0) {
381
+ console.error("❌ Failed tests:");
382
+ for (let [e, t] of c.entries()) {
383
+ let n = [t.describePath, t.itPath].filter((e) => e.length > 0).join(" > "), r = n.length > 0 ? `${n}: ` : "";
384
+ console.error(`${e + 1}. ${r}${t.message}`);
385
+ }
386
+ return 1;
387
+ }
388
+ let l = le(), u = Date.now() - r.getTime();
389
+ return console.log([
390
+ "---",
391
+ `Files ${F(`${a.length} passed`)}`,
392
+ `Evals ${F(`${l} passed`)}`,
393
+ `Start at ${F(Pe(r))}`,
394
+ `Duration ${F(`${u}ms`)}`
395
+ ].join("\n")), 0;
396
+ }
397
+ //#endregion
398
+ export { A as _, V as a, ie as c, T as d, re as f, de as g, ne as h, Se as i, C as l, w as m, Me as n, ve as o, k as p, we as r, B as s, Le as t, E as u, S as v, oe as y };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "katt",
3
- "version": "0.0.9",
3
+ "version": "0.0.11",
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.3.0",
37
+ "@biomejs/biome": "2.4.10",
38
+ "@types/node": "25.5.2",
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.3",
42
42
  "vite-plugin-dts": "4.5.4",
43
- "vitest": "4.0.18",
43
+ "vitest": "4.1.2",
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