katt 0.0.5 → 0.0.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/dist/index.js CHANGED
@@ -1,56 +1,56 @@
1
- import { r as E, c as N, a as O, p as I, b as m, l as d, d as w, g as F, e as U, f as C, s as _, h as R, i as D, j as z, k as B, m as W, n as K } from "./runCli-CDRmZ5hw.js";
2
- import { o as St } from "./runCli-CDRmZ5hw.js";
3
- import { CopilotClient as H } from "@github/copilot-sdk";
4
- import { readFile as A } from "node:fs/promises";
5
- import { resolve as j, dirname as T, isAbsolute as Y, basename as J, join as q } from "node:path";
6
- import { readFileSync as G, writeFileSync as S, mkdirSync as Q } from "node:fs";
7
- function vt(t, e) {
8
- E(() => {
9
- O(), I(t);
10
- const n = F(), r = Date.now(), i = () => F() === n, o = () => Date.now() - r;
1
+ import { r as $, c as x, p as E, a as d, l, b as p, g as w, d as N, e as P, f as h, s as A, h as S, i as j, j as _, k as O, m as L, n as I, o as U, q as R } from "./runCli-B3oIBxOl.js";
2
+ import { t as xt } from "./runCli-B3oIBxOl.js";
3
+ import { CopilotClient as z } from "@github/copilot-sdk";
4
+ import { readFile as F } from "node:fs/promises";
5
+ import { resolve as k, dirname as g, isAbsolute as B, basename as W, join as K } from "node:path";
6
+ import { readFileSync as H, writeFileSync as C, mkdirSync as Y } from "node:fs";
7
+ function wt(t, e) {
8
+ $(() => {
9
+ N(), E(t);
10
+ const n = w(), o = Date.now(), r = () => w() === n, s = () => Date.now() - o;
11
11
  try {
12
- const s = e();
13
- if (s && typeof s.then == "function") {
14
- m(
15
- s.then(() => {
16
- d(!0, o());
12
+ const i = e();
13
+ if (i && typeof i.then == "function") {
14
+ d(
15
+ i.then(() => {
16
+ l(!0, s());
17
17
  }).catch((a) => {
18
- throw d(!1, o()), a;
18
+ throw l(!1, s()), a;
19
19
  }).finally(() => {
20
- w();
20
+ p();
21
21
  })
22
22
  );
23
23
  return;
24
24
  }
25
- } catch (s) {
26
- throw d(!1, o()), w(), s;
25
+ } catch (i) {
26
+ throw l(!1, s()), p(), i;
27
27
  }
28
- d(i(), o()), w();
29
- }, N());
28
+ l(r(), s()), p();
29
+ }, x());
30
30
  }
31
- function Tt(t, e) {
32
- E(() => {
33
- U(t);
31
+ function Ct(t, e) {
32
+ $(() => {
33
+ P(t);
34
34
  try {
35
35
  const n = e();
36
36
  if (n && typeof n.then == "function") {
37
- m(
37
+ d(
38
38
  n.finally(() => {
39
- C();
39
+ h();
40
40
  })
41
41
  );
42
42
  return;
43
43
  }
44
44
  } catch (n) {
45
- throw C(), n;
45
+ throw h(), n;
46
46
  }
47
- C();
48
- }, N());
47
+ h();
48
+ }, x());
49
49
  }
50
- function V(t, e) {
50
+ function q(t, e) {
51
51
  return typeof t == "object" && t !== null && "code" in t && t.code === e;
52
52
  }
53
- function X(t) {
53
+ function J(t) {
54
54
  try {
55
55
  const e = JSON.parse(t);
56
56
  return typeof e == "object" && e !== null ? e : void 0;
@@ -59,133 +59,155 @@ function X(t) {
59
59
  return;
60
60
  }
61
61
  }
62
- async function Z() {
63
- const t = j(process.cwd(), "katt.json");
62
+ async function G() {
63
+ const t = k(process.cwd(), "katt.json");
64
64
  try {
65
- const e = await A(t, "utf8");
66
- return X(e);
65
+ const e = await F(t, "utf8");
66
+ return J(e);
67
67
  } catch (e) {
68
- if (V(e, "ENOENT"))
68
+ if (q(e, "ENOENT"))
69
69
  return;
70
70
  console.warn(`Failed to read katt.json: ${String(e)}`);
71
71
  return;
72
72
  }
73
73
  }
74
- function tt(t) {
74
+ function Q(t) {
75
75
  const e = t?.copilot;
76
76
  if (typeof e != "object" || e === null || Array.isArray(e))
77
77
  return;
78
78
  const n = {
79
79
  ...e
80
- }, r = n.model;
81
- return (typeof r != "string" || r.length === 0) && delete n.model, Object.keys(n).length > 0 ? n : void 0;
80
+ }, o = n.model;
81
+ return (typeof o != "string" || o.length === 0) && delete n.model, Object.keys(n).length > 0 ? n : void 0;
82
82
  }
83
- function et(t) {
83
+ function V(t) {
84
84
  if (!(typeof t != "number" || !Number.isFinite(t)) && !(t <= 0))
85
85
  return Math.floor(t);
86
86
  }
87
- function nt(t) {
87
+ function X(t) {
88
88
  const e = t?.prompt;
89
89
  if (!(typeof e != "object" || e === null || Array.isArray(e)))
90
- return et(e.timeoutMs);
90
+ return V(e.timeoutMs);
91
91
  }
92
- async function ot() {
93
- const t = await Z();
92
+ async function Z() {
93
+ const t = await G();
94
94
  return {
95
- copilot: tt(t),
96
- promptTimeoutMs: nt(t)
95
+ copilot: Q(t),
96
+ promptTimeoutMs: X(t)
97
97
  };
98
98
  }
99
- const rt = 6e5;
100
- function P(t) {
99
+ const tt = 6e5;
100
+ function M(t) {
101
101
  return typeof t == "string" && t.length > 0 ? t : void 0;
102
102
  }
103
- function v(t) {
103
+ function m(t) {
104
104
  if (!t)
105
105
  return;
106
106
  const e = { ...t };
107
107
  if (e.model !== void 0) {
108
- const n = P(e.model);
108
+ const n = M(e.model);
109
109
  n ? e.model = n : delete e.model;
110
110
  }
111
111
  return Object.keys(e).length > 0 ? e : void 0;
112
112
  }
113
- function M(t) {
113
+ function b(t) {
114
114
  if (!(typeof t != "number" || !Number.isFinite(t)) && !(t <= 0))
115
115
  return Math.floor(t);
116
116
  }
117
- function h(t) {
117
+ function f(t) {
118
118
  return !Number.isFinite(t) || (t ?? 0) <= 0 ? 0 : Math.floor(t ?? 0);
119
119
  }
120
- function it(t) {
121
- return h(t.inputTokens) + h(t.outputTokens) + h(t.cacheReadTokens) + h(t.cacheWriteTokens);
120
+ function et(t) {
121
+ return f(t.inputTokens) + f(t.outputTokens) + f(t.cacheReadTokens) + f(t.cacheWriteTokens);
122
122
  }
123
- async function $(t, e = {}) {
124
- const { timeoutMs: n, ...r } = e, i = await ot(), o = v(i.copilot), s = v(
125
- r
126
- ), a = v({
127
- ...o ?? {},
123
+ function nt(t, e) {
124
+ const { timeoutMs: n, ...o } = t, r = m(e.copilot), s = m(
125
+ o
126
+ ), i = m({
127
+ ...r ?? {},
128
128
  ...s ?? {}
129
- }), c = M(i.promptTimeoutMs), L = M(n) ?? c ?? rt, b = P(a?.model), g = new H({ useLoggedInUser: !0 });
130
- let p, x, y = 0;
131
- try {
132
- await g.start(), p = await g.createSession(a), x = p.on("assistant.usage", (f) => {
133
- y += it(f.data);
134
- });
135
- const l = await p.sendAndWait({ prompt: t }, L);
136
- if (!l?.data?.content)
137
- throw new Error("Copilot did not return a response.");
138
- return b && _(b), l.data.content;
139
- } finally {
140
- const l = [];
141
- if (x?.(), y > 0 && R(y), p)
142
- try {
143
- await p.destroy();
144
- } catch (f) {
145
- l.push(f);
146
- }
129
+ }), a = b(e.promptTimeoutMs), D = b(n) ?? a ?? tt;
130
+ return {
131
+ sessionOptions: i,
132
+ model: M(i?.model),
133
+ timeoutMs: D
134
+ };
135
+ }
136
+ async function ot(t, e) {
137
+ const n = [];
138
+ if (e.unsubscribeUsage?.(), e.usedTokens > 0 && j(e.usedTokens), e.session)
147
139
  try {
148
- const f = await g.stop();
149
- l.push(...f);
150
- } catch (f) {
151
- l.push(f);
140
+ await e.session.destroy();
141
+ } catch (o) {
142
+ n.push(o);
152
143
  }
153
- l.length > 0 && console.error(
154
- `Copilot cleanup encountered ${l.length} error(s).`
144
+ try {
145
+ const o = await t.stop();
146
+ n.push(...o);
147
+ } catch (o) {
148
+ n.push(o);
149
+ }
150
+ n.length > 0 && console.error(
151
+ `Copilot cleanup encountered ${n.length} error(s).`
152
+ );
153
+ }
154
+ async function y(t, e = {}) {
155
+ const n = await Z(), o = nt(e, n), r = new z({ useLoggedInUser: !0 }), s = {
156
+ session: void 0,
157
+ unsubscribeUsage: void 0,
158
+ usedTokens: 0
159
+ };
160
+ try {
161
+ await r.start(), s.session = await r.createSession(
162
+ o.sessionOptions
163
+ ), s.unsubscribeUsage = s.session.on(
164
+ "assistant.usage",
165
+ (a) => {
166
+ s.usedTokens += et(a.data);
167
+ }
168
+ );
169
+ const i = await s.session.sendAndWait(
170
+ { prompt: t },
171
+ o.timeoutMs
155
172
  );
173
+ if (!i?.data?.content)
174
+ throw new Error("Copilot did not return a response.");
175
+ return o.model && A(o.model), i.data.content;
176
+ } finally {
177
+ await ot(r, s);
156
178
  }
157
179
  }
158
- async function $t(t, e = {}) {
159
- const n = D.getStore(), r = n?.evalFile ? T(n.evalFile) : process.cwd(), i = Y(t) ? t : j(r, t), o = await A(i, "utf8");
160
- return $(o, e);
180
+ async function bt(t, e = {}) {
181
+ const n = S.getStore(), o = n?.evalFile ? g(n.evalFile) : process.cwd(), r = B(t) ? t : k(o, t), s = await F(r, "utf8");
182
+ return y(s, e);
161
183
  }
162
- function u(t) {
163
- z({
164
- describePath: W(),
165
- itPath: B(),
184
+ function c(t) {
185
+ _({
186
+ describePath: L(),
187
+ itPath: O(),
166
188
  message: t
167
189
  });
168
190
  }
169
191
  async function st(t, e) {
170
- const n = Date.now(), r = `expected '${t}' to satisfy '${e}'`, i = $(`Evaluate if the expectation is fulfiled in by the input.
192
+ const n = Date.now(), o = `expected '${t}' to satisfy '${e}'`, r = y(`Evaluate if the expectation is fulfiled in by the input.
171
193
  Expectation: "${e}".
172
194
  Input:
173
195
  ---
174
196
  ${t}
175
197
  ---
176
198
  Important: Answer with "Yes" or "No" only, without any additional text.
177
- `).then((o) => {
178
- o.includes("Yes") ? d(!0, Date.now() - n, "promptCheck") : o.includes("No") ? u(r) : u(`failed to evaluate expectation '${e}'`);
199
+ `).then((s) => {
200
+ s.includes("Yes") ? l(!0, Date.now() - n, "promptCheck") : s.includes("No") ? c(o) : c(`failed to evaluate expectation '${e}'`);
179
201
  });
180
- return m(i), i;
202
+ return d(r), r;
181
203
  }
182
- const at = 3;
183
- function ct(t) {
204
+ const rt = 3;
205
+ function it(t) {
184
206
  const e = t.match(/\b([1-5])\b/);
185
207
  return !e || !e[1] ? null : Number(e[1]);
186
208
  }
187
- async function ut(t, e, n) {
188
- const r = Date.now(), i = n?.threshold ?? at, o = $(
209
+ async function at(t, e, n) {
210
+ const o = Date.now(), r = n?.threshold ?? rt, s = y(
189
211
  `Classify the input by how "${e}" it is on a scale of 1 to 5.
190
212
  1 means "not ${e}" and 5 means "very ${e}".
191
213
  Return only a single number: 1, 2, 3, 4, or 5.
@@ -195,129 +217,141 @@ Input:
195
217
  ${t}
196
218
  ---`,
197
219
  n?.model ? { model: n.model } : void 0
198
- ).then((s) => {
199
- const a = ct(s);
220
+ ).then((i) => {
221
+ const a = it(i);
200
222
  if (a === null) {
201
- u(
202
- `failed to classify as '${e}'. Evaluator returned '${s}'`
223
+ c(
224
+ `failed to classify as '${e}'. Evaluator returned '${i}'`
203
225
  );
204
226
  return;
205
227
  }
206
- const c = `expected response to be classified as '${e}' with score >= ${i}, got ${a}`;
207
- if (a < i) {
208
- u(c);
228
+ const u = `expected response to be classified as '${e}' with score >= ${r}, got ${a}`;
229
+ if (a < r) {
230
+ c(u);
209
231
  return;
210
232
  }
211
- d(
233
+ l(
212
234
  !0,
213
- Date.now() - r,
235
+ Date.now() - o,
214
236
  "toBeClassifiedAs"
215
237
  );
216
238
  });
217
- return m(o), o;
239
+ return d(s), s;
218
240
  }
219
- function lt(t, e) {
241
+ function ct(t, e) {
220
242
  const n = `expected '${t}' to include '${e}'`;
221
- t.includes(e) || u(n);
243
+ t.includes(e) || c(n);
244
+ }
245
+ function v(t) {
246
+ const e = t.trim().replace(/[<>:"/\\|?*\x00-\x1f]/g, "_").replace(/\s+/g, "_");
247
+ return e.length > 0 ? e : "unnamed";
248
+ }
249
+ function ut() {
250
+ const t = U().map(
251
+ (o) => v(o.description)
252
+ ), e = R().map(
253
+ (o) => v(o.description)
254
+ ), n = [...t, ...e];
255
+ return n.length === 0 ? "root" : n.join("__");
222
256
  }
223
- function ft(t) {
224
- const n = J(t).replace(/\.eval\.[^./\\]+$/, "");
225
- return q(
226
- T(t),
257
+ function lt(t) {
258
+ const n = W(t).replace(/\.eval\.[^./\\]+$/, ""), o = ut();
259
+ return K(
260
+ g(t),
227
261
  "__snapshots__",
228
- `${n}.snap.md`
262
+ `${n}__${o}.snap.md`
229
263
  );
230
264
  }
231
- function k(t) {
265
+ function T(t) {
232
266
  return t.split(/\r?\n/);
233
267
  }
234
- function dt(t, e) {
268
+ function ft(t, e) {
235
269
  if (t === e)
236
270
  return " (no diff)";
237
- const n = k(t), r = k(e), i = Math.max(n.length, r.length), o = [];
238
- for (let s = 0; s < i; s += 1) {
239
- const a = n[s], c = r[s];
240
- if (a !== c) {
241
- if (a === void 0 && c !== void 0) {
242
- o.push(`+ ${c}`);
271
+ const n = T(t), o = T(e), r = Math.max(n.length, o.length), s = [];
272
+ for (let i = 0; i < r; i += 1) {
273
+ const a = n[i], u = o[i];
274
+ if (a !== u) {
275
+ if (a === void 0 && u !== void 0) {
276
+ s.push(`+ ${u}`);
243
277
  continue;
244
278
  }
245
- if (a !== void 0 && c === void 0) {
246
- o.push(`- ${a}`);
279
+ if (a !== void 0 && u === void 0) {
280
+ s.push(`- ${a}`);
247
281
  continue;
248
282
  }
249
- o.push(`- ${a ?? ""}`), o.push(`+ ${c ?? ""}`);
283
+ s.push(`- ${a ?? ""}`), s.push(`+ ${u ?? ""}`);
250
284
  }
251
285
  }
252
- return o.join(`
286
+ return s.join(`
253
287
  `);
254
288
  }
255
- function pt(t) {
256
- const e = D.getStore()?.evalFile;
289
+ function dt(t) {
290
+ const e = S.getStore()?.evalFile;
257
291
  if (!e) {
258
- u(
292
+ c(
259
293
  "toMatchSnapshot can only be used while running an eval file."
260
294
  );
261
295
  return;
262
296
  }
263
- const n = ft(e);
297
+ const n = lt(e);
264
298
  try {
265
- const r = G(n, "utf8");
266
- if (r === t)
299
+ const o = H(n, "utf8");
300
+ if (o === t)
267
301
  return;
268
- if (K()) {
269
- S(n, t, "utf8");
302
+ if (I()) {
303
+ C(n, t, "utf8");
270
304
  return;
271
305
  }
272
- const i = dt(r, t);
273
- u(
306
+ const r = ft(o, t);
307
+ c(
274
308
  [
275
309
  `Snapshot mismatch at ${n}`,
276
310
  "",
277
311
  "Diff:",
278
- i,
312
+ r,
279
313
  "",
280
314
  "Run katt with --update-snapshots (or -u) to accept this change."
281
315
  ].join(`
282
316
  `)
283
317
  );
284
- } catch (r) {
285
- if (r.code !== "ENOENT") {
286
- u(
287
- `Failed to read snapshot at ${n}: ${String(r)}`
318
+ } catch (o) {
319
+ if (o.code !== "ENOENT") {
320
+ c(
321
+ `Failed to read snapshot at ${n}: ${String(o)}`
288
322
  );
289
323
  return;
290
324
  }
291
325
  try {
292
- Q(T(n), { recursive: !0 }), S(n, t, "utf8");
293
- } catch (o) {
294
- u(
295
- `Failed to write snapshot at ${n}: ${String(o)}`
326
+ Y(g(n), { recursive: !0 }), C(n, t, "utf8");
327
+ } catch (s) {
328
+ c(
329
+ `Failed to write snapshot at ${n}: ${String(s)}`
296
330
  );
297
331
  }
298
332
  }
299
333
  }
300
- function bt(t) {
334
+ function vt(t) {
301
335
  return {
302
336
  toContain: (e) => {
303
- lt(t, e);
337
+ ct(t, e);
304
338
  },
305
339
  toMatchSnapshot: () => {
306
- pt(t);
340
+ dt(t);
307
341
  },
308
342
  promptCheck: async (e) => {
309
343
  await st(t, e);
310
344
  },
311
345
  toBeClassifiedAs: async (e, n) => {
312
- await ut(t, e, n);
346
+ await at(t, e, n);
313
347
  }
314
348
  };
315
349
  }
316
350
  export {
317
- Tt as describe,
318
- bt as expect,
319
- vt as it,
320
- $ as prompt,
321
- $t as promptFile,
322
- St as runCli
351
+ Ct as describe,
352
+ vt as expect,
353
+ wt as it,
354
+ y as prompt,
355
+ bt as promptFile,
356
+ xt as runCli
323
357
  };
package/dist/katt.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { o as r } from "./runCli-CDRmZ5hw.js";
2
+ import { t as r } from "./runCli-B3oIBxOl.js";
3
3
  r().then((e) => {
4
4
  process.exit(e);
5
5
  }).catch((e) => {
@@ -0,0 +1,317 @@
1
+ import { fileURLToPath as Z, pathToFileURL as y } from "node:url";
2
+ import { readdir as N } from "node:fs/promises";
3
+ import { resolve as M } from "node:path";
4
+ import { AsyncLocalStorage as v } from "node:async_hooks";
5
+ import { readFileSync as X } from "node:fs";
6
+ const H = /\.eval\.(js|ts)$/, R = /* @__PURE__ */ new Set([".git", "node_modules"]);
7
+ async function w(t) {
8
+ const e = await N(t, { withFileTypes: !0 }), n = [];
9
+ return await Promise.all(
10
+ e.map(async (i) => {
11
+ const s = M(t, i.name);
12
+ if (i.isDirectory()) {
13
+ if (R.has(i.name))
14
+ return;
15
+ n.push(...await w(s));
16
+ return;
17
+ }
18
+ i.isFile() && H.test(i.name) && n.push(s);
19
+ })
20
+ ), n;
21
+ }
22
+ const j = new v(), W = {
23
+ describeStack: [],
24
+ itStack: [],
25
+ tokenUsageStack: [],
26
+ modelStack: []
27
+ };
28
+ let b = 0, L = 0;
29
+ const p = [], f = [];
30
+ let k = 0;
31
+ function o() {
32
+ return j.getStore() ?? W;
33
+ }
34
+ function J(t) {
35
+ return {
36
+ describeStack: [...t.describeStack],
37
+ itStack: [...t.itStack],
38
+ tokenUsageStack: [...t.tokenUsageStack],
39
+ modelStack: [...t.modelStack]
40
+ };
41
+ }
42
+ function U() {
43
+ return b += 1, `d${b}`;
44
+ }
45
+ function G() {
46
+ return L += 1, `i${L}`;
47
+ }
48
+ function B(t) {
49
+ return t.tokenUsageStack.length - 1;
50
+ }
51
+ function F(t) {
52
+ return t.modelStack.length - 1;
53
+ }
54
+ function bt(t, e) {
55
+ const n = e ?? J(o());
56
+ return j.run(n, t);
57
+ }
58
+ function Lt() {
59
+ return J(o());
60
+ }
61
+ function $t(t) {
62
+ o().describeStack.push({ id: U(), description: t });
63
+ }
64
+ function vt() {
65
+ o().describeStack.pop();
66
+ }
67
+ function O() {
68
+ return o().describeStack.map((t) => t.description).join(" > ");
69
+ }
70
+ function wt() {
71
+ return [...o().describeStack];
72
+ }
73
+ function jt(t) {
74
+ const e = o();
75
+ e.itStack.push({ id: G(), description: t }), e.tokenUsageStack.push(0), e.modelStack.push(void 0);
76
+ }
77
+ function Jt() {
78
+ const t = o();
79
+ t.itStack.pop(), t.tokenUsageStack.pop(), t.modelStack.pop();
80
+ }
81
+ function Y() {
82
+ return o().itStack.map((t) => t.description).join(" > ");
83
+ }
84
+ function Bt() {
85
+ return [...o().itStack];
86
+ }
87
+ function Ft(t) {
88
+ if (!Number.isFinite(t) || t <= 0)
89
+ return;
90
+ const e = o(), n = B(e);
91
+ n < 0 || (e.tokenUsageStack[n] += t);
92
+ }
93
+ function Q() {
94
+ const t = o(), e = B(t);
95
+ return e < 0 ? 0 : t.tokenUsageStack[e] ?? 0;
96
+ }
97
+ function xt(t) {
98
+ if (t.length === 0)
99
+ return;
100
+ const e = o(), n = F(e);
101
+ n < 0 || (e.modelStack[n] = t);
102
+ }
103
+ function V() {
104
+ const t = o(), e = F(t);
105
+ if (!(e < 0))
106
+ return t.modelStack[e];
107
+ }
108
+ function Tt(t) {
109
+ p.push(t);
110
+ }
111
+ function Zt() {
112
+ k += 1;
113
+ }
114
+ function K() {
115
+ return k;
116
+ }
117
+ function P() {
118
+ k = 0;
119
+ }
120
+ function yt(t) {
121
+ f.push(t);
122
+ }
123
+ function E() {
124
+ return [...f];
125
+ }
126
+ function Nt() {
127
+ return f.length;
128
+ }
129
+ function z() {
130
+ f.length = 0;
131
+ }
132
+ async function D() {
133
+ const t = [];
134
+ for (; p.length > 0; ) {
135
+ const e = p.splice(0, p.length), n = await Promise.allSettled(e);
136
+ t.push(...n);
137
+ }
138
+ return t;
139
+ }
140
+ const _ = "\x1B[1;36m", q = "\x1B[33m", tt = "\x1B[38;5;208m", et = "\x1B[1;38;5;208m", m = "\x1B[0m";
141
+ function r(t) {
142
+ return `${_}${t}${m}`;
143
+ }
144
+ function C(t) {
145
+ return `${q}${t}${m}`;
146
+ }
147
+ function $(t) {
148
+ return `${tt}${t}${m}`;
149
+ }
150
+ function nt(t) {
151
+ return `${et}${t}${m}`;
152
+ }
153
+ let A = "";
154
+ function it() {
155
+ A = "";
156
+ }
157
+ function ot({
158
+ suitePath: t,
159
+ casePath: e,
160
+ didPass: n,
161
+ durationMs: i,
162
+ model: s,
163
+ tokenUsage: c
164
+ }) {
165
+ const l = t.length > 0 ? t : "(root)", u = e.length > 0 ? e : "(root)";
166
+ A !== l && (console.log(`Suite "${r(l)}"`), A = l);
167
+ const g = n ? "✅ Passed in" : "❌ Failed in", I = [
168
+ `Test "${r(u)}"`,
169
+ `- ${g} ${r(`${i}ms`)}`
170
+ ];
171
+ s && I.push(`- Model ${r(s)}`), (c ?? 0) > 0 && I.push(`- Tokens used ${r(String(c))}`), I.push("---"), console.log(I.join(`
172
+ `));
173
+ }
174
+ function Mt(t, e, n = "(root)") {
175
+ const i = Y();
176
+ ot({
177
+ suitePath: O(),
178
+ casePath: i.length > 0 ? i : n,
179
+ didPass: t,
180
+ durationMs: e,
181
+ model: V(),
182
+ tokenUsage: Q()
183
+ });
184
+ }
185
+ const st = new v(), h = new URL("data:application/json;base64,ewogICJuYW1lIjogImthdHQiLAogICJ2ZXJzaW9uIjogIjAuMC41IiwKICAiZGVzY3JpcHRpb24iOiAiQ0xJIHRvb2wgdGhhdCB0ZXN0cyB0aGUgb3V0cHV0IG9mIGFnZW50aWMgQUkgdG9vbHMiLAogICJrZXl3b3JkcyI6IFsKICAgICJjbGkiLAogICAgImFpIiwKICAgICJhZ2VudGljLWFpIiwKICAgICJ0ZXN0aW5nIiwKICAgICJldmFsdWF0aW9uIgogIF0sCiAgImF1dGhvciI6ICJSYXBoYWVsIFBvcnRvIChodHRwczovL2dpdGh1Yi5jb20vcmFwaGFlbHBvcikiLAogICJsaWNlbnNlIjogIk1JVCIsCiAgInR5cGUiOiAibW9kdWxlIiwKICAibWFpbiI6ICJkaXN0L2luZGV4LmpzIiwKICAiZXhwb3J0cyI6IHsKICAgICIuIjogewogICAgICAidHlwZXMiOiAiLi9kaXN0L2luZGV4LmQudHMiLAogICAgICAiaW1wb3J0IjogIi4vZGlzdC9pbmRleC5qcyIKICAgIH0KICB9LAogICJiaW4iOiB7CiAgICAia2F0dCI6ICJkaXN0L2thdHQuanMiCiAgfSwKICAic2NyaXB0cyI6IHsKICAgICJidWlsZCI6ICJ2aXRlIGJ1aWxkIiwKICAgICJkZXYiOiAidHN4IHNyYy9pbmRleC50cyIsCiAgICAibGludCI6ICJiaW9tZSBsaW50IC4vc3JjIiwKICAgICJmb3JtYXQiOiAiYmlvbWUgZm9ybWF0IC0td3JpdGUgLi9zcmMiLAogICAgInRlc3QiOiAidml0ZXN0IiwKICAgICJ0eXBlY2hlY2siOiAidHNjIC1wIHRzY29uZmlnLmpzb24gLS1ub0VtaXQiLAogICAgInRlc3Q6YnVpbGQiOiAibm9kZSAuL2Rpc3Qva2F0dC5qcyIKICB9LAogICJ0eXBlcyI6ICJkaXN0L2luZGV4LmQudHMiLAogICJkZXZEZXBlbmRlbmNpZXMiOiB7CiAgICAiQGJpb21lanMvYmlvbWUiOiAiMS45LjQiLAogICAgIkB0eXBlcy9ub2RlIjogIjI1LjIuMCIsCiAgICAidHN4IjogIjQuMjEuMCIsCiAgICAidHlwZXNjcmlwdCI6ICI1LjguMiIsCiAgICAidml0ZSI6ICI3LjMuMSIsCiAgICAidml0ZS1wbHVnaW4tZHRzIjogIjQuNS40IiwKICAgICJ2aXRlc3QiOiAiMy4yLjQiLAogICAgInZzY29kZS1qc29ucnBjIjogIl44LjIuMSIKICB9LAogICJkZXBlbmRlbmNpZXMiOiB7CiAgICAiQGdpdGh1Yi9jb3BpbG90LXNkayI6ICJeMC4xLjIxIgogIH0sCiAgImJ1Z3MiOiB7CiAgICAidXJsIjogImh0dHBzOi8vZ2l0aHViLmNvbS9yYXBoYWVscG9yL2thdHQvaXNzdWVzIgogIH0sCiAgImhvbWVwYWdlIjogImh0dHBzOi8vZ2l0aHViLmNvbS9yYXBoYWVscG9yL2thdHQiCn0K", import.meta.url);
186
+ let d;
187
+ function at() {
188
+ if (d !== void 0)
189
+ return d;
190
+ try {
191
+ const t = h.protocol === "data:" ? rt(h) : X(Z(h), "utf8"), e = JSON.parse(t);
192
+ d = typeof e.version == "string" ? e.version : "unknown";
193
+ } catch {
194
+ d = "unknown";
195
+ }
196
+ return d;
197
+ }
198
+ function rt(t) {
199
+ const e = t.pathname.indexOf(",");
200
+ if (e < 0)
201
+ throw new Error("Invalid data URL.");
202
+ const n = t.pathname.slice(0, e), i = t.pathname.slice(e + 1);
203
+ return n.includes(";base64") ? Buffer.from(i, "base64").toString("utf8") : decodeURIComponent(i);
204
+ }
205
+ function ct() {
206
+ const t = " ██╗ ██╗ █████╗ ████████╗████████╗", e = " ██║ ██╔╝██╔══██╗╚══██╔══╝╚══██╔══╝", n = " █████╔╝ ███████║ ██║ ██║", i = " ██╔═██╗ ██╔══██║ ██║ ██║", s = " ██║ ██╗██║ ██║ ██║ ██║", c = " ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝", l = `v${at()}`, u = Math.max(
207
+ 0,
208
+ Math.floor((t.length - l.length) / 2)
209
+ ), g = `${" ".repeat(u)}${l}`;
210
+ console.log(`
211
+ ${C(t)}
212
+ ${C(e)}
213
+ ${C(n)}
214
+ ${$(i)}
215
+ ${$(s)}
216
+ ${nt(c)}
217
+ ${C(g)}
218
+ `);
219
+ }
220
+ let x = !1;
221
+ function lt(t) {
222
+ x = t;
223
+ }
224
+ function Xt() {
225
+ return x;
226
+ }
227
+ function ut(t) {
228
+ const e = String(t.getHours()).padStart(2, "0"), n = String(t.getMinutes()).padStart(2, "0"), i = String(t.getSeconds()).padStart(2, "0");
229
+ return `${e}:${n}:${i}`;
230
+ }
231
+ function gt(t) {
232
+ return t.includes("--update-snapshots") || t.includes("-u");
233
+ }
234
+ function It(t) {
235
+ return [t.describePath, t.itPath].filter((e) => e.length > 0).join(" > ");
236
+ }
237
+ function dt(t) {
238
+ for (const e of t)
239
+ console.error(`Error executing ${e.file}: ${String(e.reason)}`);
240
+ }
241
+ function Ct(t) {
242
+ for (const e of t)
243
+ console.error(`Error executing async test: ${String(e.reason)}`);
244
+ }
245
+ function pt(t) {
246
+ console.error("❌ Failed tests:");
247
+ for (const [e, n] of t.entries()) {
248
+ const i = It(n), s = i.length > 0 ? `${i}: ` : "";
249
+ console.error(`${e + 1}. ${s}${n.message}`);
250
+ }
251
+ }
252
+ function ft(t, e, n, i) {
253
+ return [
254
+ "---",
255
+ `${r("Files")} ${t} passed`,
256
+ `${r("Evals")} ${e} passed`,
257
+ `${r("Start at")} ${ut(n)}`,
258
+ `${r("Duration")} ${i}ms`
259
+ ].join(`
260
+ `);
261
+ }
262
+ async function Ht() {
263
+ const t = process.argv.slice(2), e = gt(t);
264
+ lt(e), ct();
265
+ const n = /* @__PURE__ */ new Date();
266
+ it(), z(), P();
267
+ const i = await w(process.cwd());
268
+ if (i.length === 0)
269
+ return console.log("No .eval.js or .eval.ts files found."), 1;
270
+ const c = (await Promise.allSettled(
271
+ i.map(
272
+ (a) => st.run(
273
+ { evalFile: a },
274
+ () => import(y(a).href)
275
+ )
276
+ )
277
+ )).map((a, S) => ({ result: a, file: i[S] })).filter(({ result: a }) => a.status === "rejected").map(({ result: a, file: S }) => ({
278
+ file: S,
279
+ reason: a.status === "rejected" ? a.reason : void 0
280
+ }));
281
+ if (c.length > 0)
282
+ return dt(c), 1;
283
+ const u = (await D()).filter(
284
+ (a) => a.status === "rejected"
285
+ );
286
+ if (u.length > 0)
287
+ return Ct(u), 1;
288
+ const g = E();
289
+ if (g.length > 0)
290
+ return pt(g), 1;
291
+ const I = K(), T = Date.now() - n.getTime();
292
+ return console.log(
293
+ ft(i.length, I, n, T)
294
+ ), 0;
295
+ }
296
+ export {
297
+ Tt as a,
298
+ Jt as b,
299
+ Lt as c,
300
+ Zt as d,
301
+ $t as e,
302
+ vt as f,
303
+ Nt as g,
304
+ st as h,
305
+ Ft as i,
306
+ yt as j,
307
+ Y as k,
308
+ Mt as l,
309
+ O as m,
310
+ Xt as n,
311
+ wt as o,
312
+ jt as p,
313
+ Bt as q,
314
+ bt as r,
315
+ xt as s,
316
+ Ht as t
317
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "katt",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "description": "CLI tool that tests the output of agentic AI tools",
5
5
  "keywords": [
6
6
  "cli",
@@ -1,288 +0,0 @@
1
- import { fileURLToPath as x, pathToFileURL as y } from "node:url";
2
- import { readdir as X } from "node:fs/promises";
3
- import { resolve as H } from "node:path";
4
- import { AsyncLocalStorage as j } from "node:async_hooks";
5
- import { readFileSync as M } from "node:fs";
6
- const R = /\.eval\.(js|ts)$/, W = /* @__PURE__ */ new Set([".git", "node_modules"]);
7
- async function v(t) {
8
- const e = await X(t, { withFileTypes: !0 }), n = [];
9
- return await Promise.all(
10
- e.map(async (o) => {
11
- const a = H(t, o.name);
12
- if (o.isDirectory()) {
13
- if (W.has(o.name))
14
- return;
15
- n.push(...await v(a));
16
- return;
17
- }
18
- o.isFile() && R.test(o.name) && n.push(a);
19
- })
20
- ), n;
21
- }
22
- const J = new j(), G = {
23
- describeStack: [],
24
- itStack: [],
25
- tokenUsageStack: [],
26
- modelStack: []
27
- };
28
- let L = 0, $ = 0;
29
- const p = [], m = [];
30
- let k = 0;
31
- function s() {
32
- return J.getStore() ?? G;
33
- }
34
- function B(t) {
35
- return {
36
- describeStack: [...t.describeStack],
37
- itStack: [...t.itStack],
38
- tokenUsageStack: [...t.tokenUsageStack],
39
- modelStack: [...t.modelStack]
40
- };
41
- }
42
- function U() {
43
- return L += 1, `d${L}`;
44
- }
45
- function O() {
46
- return $ += 1, `i${$}`;
47
- }
48
- function mt(t, e) {
49
- const n = e ?? B(s());
50
- return J.run(n, t);
51
- }
52
- function ht() {
53
- return B(s());
54
- }
55
- function St(t) {
56
- s().describeStack.push({ id: U(), description: t });
57
- }
58
- function At() {
59
- s().describeStack.pop();
60
- }
61
- function Y() {
62
- return s().describeStack.map((t) => t.description).join(" > ");
63
- }
64
- function kt(t) {
65
- s().itStack.push({ id: O(), description: t }), s().tokenUsageStack.push(0), s().modelStack.push(void 0);
66
- }
67
- function bt() {
68
- s().itStack.pop(), s().tokenUsageStack.pop(), s().modelStack.pop();
69
- }
70
- function Q() {
71
- return s().itStack.map((t) => t.description).join(" > ");
72
- }
73
- function Lt(t) {
74
- if (!Number.isFinite(t) || t <= 0)
75
- return;
76
- const e = s(), n = e.tokenUsageStack.length - 1;
77
- n < 0 || (e.tokenUsageStack[n] += t);
78
- }
79
- function V() {
80
- const t = s(), e = t.tokenUsageStack.length - 1;
81
- return e < 0 ? 0 : t.tokenUsageStack[e] ?? 0;
82
- }
83
- function $t(t) {
84
- if (t.length === 0)
85
- return;
86
- const e = s(), n = e.modelStack.length - 1;
87
- n < 0 || (e.modelStack[n] = t);
88
- }
89
- function K() {
90
- const t = s(), e = t.modelStack.length - 1;
91
- if (!(e < 0))
92
- return t.modelStack[e];
93
- }
94
- function wt(t) {
95
- p.push(t);
96
- }
97
- function jt() {
98
- k += 1;
99
- }
100
- function P() {
101
- return k;
102
- }
103
- function z() {
104
- k = 0;
105
- }
106
- function vt(t) {
107
- m.push(t);
108
- }
109
- function E() {
110
- return [...m];
111
- }
112
- function Jt() {
113
- return m.length;
114
- }
115
- function D() {
116
- m.length = 0;
117
- }
118
- async function _() {
119
- const t = [];
120
- for (; p.length > 0; ) {
121
- const e = p.splice(0, p.length), n = await Promise.allSettled(e);
122
- t.push(...n);
123
- }
124
- return t;
125
- }
126
- const q = "\x1B[1;36m", tt = "\x1B[33m", et = "\x1B[38;5;208m", nt = "\x1B[1;38;5;208m", h = "\x1B[0m";
127
- function c(t) {
128
- return `${q}${t}${h}`;
129
- }
130
- function f(t) {
131
- return `${tt}${t}${h}`;
132
- }
133
- function w(t) {
134
- return `${et}${t}${h}`;
135
- }
136
- function ot(t) {
137
- return `${nt}${t}${h}`;
138
- }
139
- let A = "";
140
- function it() {
141
- A = "";
142
- }
143
- function st({
144
- suitePath: t,
145
- casePath: e,
146
- didPass: n,
147
- durationMs: o,
148
- model: a,
149
- tokenUsage: r
150
- }) {
151
- const l = t.length > 0 ? t : "(root)", g = e.length > 0 ? e : "(root)";
152
- A !== l && (console.log(`Suite "${c(l)}"`), A = l);
153
- const I = n ? "✅ Passed in" : "❌ Failed in", d = [
154
- `Test "${c(g)}"`,
155
- `- ${I} ${c(`${o}ms`)}`
156
- ];
157
- a && d.push(`- Model ${c(a)}`), (r ?? 0) > 0 && d.push(`- Tokens used ${c(String(r))}`), d.push("---"), console.log(d.join(`
158
- `));
159
- }
160
- function Bt(t, e, n = "(root)") {
161
- const o = Q();
162
- st({
163
- suitePath: Y(),
164
- casePath: o.length > 0 ? o : n,
165
- didPass: t,
166
- durationMs: e,
167
- model: K(),
168
- tokenUsage: V()
169
- });
170
- }
171
- const at = new j(), S = new URL("data:application/json;base64,ewogICJuYW1lIjogImthdHQiLAogICJ2ZXJzaW9uIjogIjAuMC40IiwKICAiZGVzY3JpcHRpb24iOiAiQ0xJIHRvb2wgdGhhdCB0ZXN0cyB0aGUgb3V0cHV0IG9mIGFnZW50aWMgQUkgdG9vbHMiLAogICJrZXl3b3JkcyI6IFsKICAgICJjbGkiLAogICAgImFpIiwKICAgICJhZ2VudGljLWFpIiwKICAgICJ0ZXN0aW5nIiwKICAgICJldmFsdWF0aW9uIgogIF0sCiAgImF1dGhvciI6ICJSYXBoYWVsIFBvcnRvIChodHRwczovL2dpdGh1Yi5jb20vcmFwaGFlbHBvcikiLAogICJsaWNlbnNlIjogIk1JVCIsCiAgInR5cGUiOiAibW9kdWxlIiwKICAibWFpbiI6ICJkaXN0L2luZGV4LmpzIiwKICAiZXhwb3J0cyI6IHsKICAgICIuIjogewogICAgICAidHlwZXMiOiAiLi9kaXN0L2luZGV4LmQudHMiLAogICAgICAiaW1wb3J0IjogIi4vZGlzdC9pbmRleC5qcyIKICAgIH0KICB9LAogICJiaW4iOiB7CiAgICAia2F0dCI6ICJkaXN0L2thdHQuanMiCiAgfSwKICAic2NyaXB0cyI6IHsKICAgICJidWlsZCI6ICJ2aXRlIGJ1aWxkIiwKICAgICJkZXYiOiAidHN4IHNyYy9pbmRleC50cyIsCiAgICAibGludCI6ICJiaW9tZSBsaW50IC4vc3JjIiwKICAgICJmb3JtYXQiOiAiYmlvbWUgZm9ybWF0IC0td3JpdGUgLi9zcmMiLAogICAgInRlc3QiOiAidml0ZXN0IiwKICAgICJ0eXBlY2hlY2siOiAidHNjIC1wIHRzY29uZmlnLmpzb24gLS1ub0VtaXQiLAogICAgInRlc3Q6YnVpbGQiOiAibm9kZSAuL2Rpc3Qva2F0dC5qcyIKICB9LAogICJ0eXBlcyI6ICJkaXN0L2luZGV4LmQudHMiLAogICJkZXZEZXBlbmRlbmNpZXMiOiB7CiAgICAiQGJpb21lanMvYmlvbWUiOiAiMS45LjQiLAogICAgIkB0eXBlcy9ub2RlIjogIjI1LjIuMCIsCiAgICAidHN4IjogIjQuMjEuMCIsCiAgICAidHlwZXNjcmlwdCI6ICI1LjguMiIsCiAgICAidml0ZSI6ICI3LjMuMSIsCiAgICAidml0ZS1wbHVnaW4tZHRzIjogIjQuNS40IiwKICAgICJ2aXRlc3QiOiAiMy4yLjQiLAogICAgInZzY29kZS1qc29ucnBjIjogIl44LjIuMSIKICB9LAogICJkZXBlbmRlbmNpZXMiOiB7CiAgICAiQGdpdGh1Yi9jb3BpbG90LXNkayI6ICJeMC4xLjIxIgogIH0sCiAgImJ1Z3MiOiB7CiAgICAidXJsIjogImh0dHBzOi8vZ2l0aHViLmNvbS9yYXBoYWVscG9yL2thdHQvaXNzdWVzIgogIH0sCiAgImhvbWVwYWdlIjogImh0dHBzOi8vZ2l0aHViLmNvbS9yYXBoYWVscG9yL2thdHQiCn0K", import.meta.url);
172
- let C;
173
- function ct() {
174
- if (C !== void 0)
175
- return C;
176
- try {
177
- const t = S.protocol === "data:" ? rt(S) : M(x(S), "utf8"), e = JSON.parse(t);
178
- C = typeof e.version == "string" ? e.version : "unknown";
179
- } catch {
180
- C = "unknown";
181
- }
182
- return C;
183
- }
184
- function rt(t) {
185
- const e = t.pathname.indexOf(",");
186
- if (e < 0)
187
- throw new Error("Invalid data URL.");
188
- const n = t.pathname.slice(0, e), o = t.pathname.slice(e + 1);
189
- return n.includes(";base64") ? Buffer.from(o, "base64").toString("utf8") : decodeURIComponent(o);
190
- }
191
- function lt() {
192
- const t = " ██╗ ██╗ █████╗ ████████╗████████╗", e = " ██║ ██╔╝██╔══██╗╚══██╔══╝╚══██╔══╝", n = " █████╔╝ ███████║ ██║ ██║", o = " ██╔═██╗ ██╔══██║ ██║ ██║", a = " ██║ ██╗██║ ██║ ██║ ██║", r = " ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝", l = `v${ct()}`, g = Math.max(
193
- 0,
194
- Math.floor((t.length - l.length) / 2)
195
- ), I = `${" ".repeat(g)}${l}`;
196
- console.log(`
197
- ${f(t)}
198
- ${f(e)}
199
- ${f(n)}
200
- ${w(o)}
201
- ${w(a)}
202
- ${ot(r)}
203
- ${f(I)}
204
- `);
205
- }
206
- let Z = !1;
207
- function ut(t) {
208
- Z = t;
209
- }
210
- function Zt() {
211
- return Z;
212
- }
213
- function gt(t) {
214
- const e = String(t.getHours()).padStart(2, "0"), n = String(t.getMinutes()).padStart(2, "0"), o = String(t.getSeconds()).padStart(2, "0");
215
- return `${e}:${n}:${o}`;
216
- }
217
- async function Ft() {
218
- const t = process.argv.slice(2), e = t.includes("--update-snapshots") || t.includes("-u");
219
- ut(e), lt();
220
- const n = /* @__PURE__ */ new Date();
221
- it(), D(), z();
222
- const o = await v(process.cwd());
223
- if (o.length === 0)
224
- return console.log("No .eval.js or .eval.ts files found."), 1;
225
- const r = (await Promise.allSettled(
226
- o.map(
227
- (i) => at.run(
228
- { evalFile: i },
229
- () => import(y(i).href)
230
- )
231
- )
232
- )).map((i, u) => ({ result: i, file: o[u] })).filter(({ result: i }) => i.status === "rejected");
233
- if (r.length > 0) {
234
- for (const i of r) {
235
- const u = i.result.status === "rejected" ? i.result.reason : void 0;
236
- console.error(`Error executing ${i.file}: ${String(u)}`);
237
- }
238
- return 1;
239
- }
240
- const g = (await _()).filter(
241
- (i) => i.status === "rejected"
242
- );
243
- if (g.length > 0) {
244
- for (const i of g)
245
- i.status === "rejected" && console.error(`Error executing async test: ${String(i.reason)}`);
246
- return 1;
247
- }
248
- const I = E();
249
- if (I.length > 0) {
250
- console.error("❌ Failed tests:");
251
- for (const [i, u] of I.entries()) {
252
- const b = [u.describePath, u.itPath].filter((T) => T.length > 0).join(" > "), N = b.length > 0 ? `${b}: ` : "";
253
- console.error(`${i + 1}. ${N}${u.message}`);
254
- }
255
- return 1;
256
- }
257
- const d = P(), F = Date.now() - n.getTime();
258
- return console.log(
259
- [
260
- "---",
261
- `${c("Files")} ${o.length} passed`,
262
- `${c("Evals")} ${d} passed`,
263
- `${c("Start at")} ${gt(n)}`,
264
- `${c("Duration")} ${F}ms`
265
- ].join(`
266
- `)
267
- ), 0;
268
- }
269
- export {
270
- jt as a,
271
- wt as b,
272
- ht as c,
273
- bt as d,
274
- St as e,
275
- At as f,
276
- Jt as g,
277
- Lt as h,
278
- at as i,
279
- vt as j,
280
- Q as k,
281
- Bt as l,
282
- Y as m,
283
- Zt as n,
284
- Ft as o,
285
- kt as p,
286
- mt as r,
287
- $t as s
288
- };