@ikarmic/forge-eval 0.0.0-stage → 4.5.0

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.
Files changed (103) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +95 -2
  3. package/dist/bin/forge-eval.d.ts +3 -0
  4. package/dist/bin/forge-eval.d.ts.map +1 -0
  5. package/dist/bin/forge-eval.js +138 -0
  6. package/dist/bin/forge-eval.js.map +1 -0
  7. package/dist/graders/behavior.d.ts +57 -0
  8. package/dist/graders/behavior.d.ts.map +1 -0
  9. package/dist/graders/behavior.js +154 -0
  10. package/dist/graders/behavior.js.map +1 -0
  11. package/dist/graders/content.d.ts +59 -0
  12. package/dist/graders/content.d.ts.map +1 -0
  13. package/dist/graders/content.js +135 -0
  14. package/dist/graders/content.js.map +1 -0
  15. package/dist/graders/fs.d.ts +24 -0
  16. package/dist/graders/fs.d.ts.map +1 -0
  17. package/dist/graders/fs.js +134 -0
  18. package/dist/graders/fs.js.map +1 -0
  19. package/dist/graders/index.d.ts +15 -0
  20. package/dist/graders/index.d.ts.map +1 -0
  21. package/dist/graders/index.js +19 -0
  22. package/dist/graders/index.js.map +1 -0
  23. package/dist/graders/metrics.d.ts +59 -0
  24. package/dist/graders/metrics.d.ts.map +1 -0
  25. package/dist/graders/metrics.js +70 -0
  26. package/dist/graders/metrics.js.map +1 -0
  27. package/dist/graders/schema.d.ts +87 -0
  28. package/dist/graders/schema.d.ts.map +1 -0
  29. package/dist/graders/schema.js +157 -0
  30. package/dist/graders/schema.js.map +1 -0
  31. package/dist/graders/shell.d.ts +36 -0
  32. package/dist/graders/shell.d.ts.map +1 -0
  33. package/dist/graders/shell.js +72 -0
  34. package/dist/graders/shell.js.map +1 -0
  35. package/dist/graders/text.d.ts +28 -0
  36. package/dist/graders/text.d.ts.map +1 -0
  37. package/dist/graders/text.js +70 -0
  38. package/dist/graders/text.js.map +1 -0
  39. package/dist/graders/types.d.ts +81 -0
  40. package/dist/graders/types.d.ts.map +1 -0
  41. package/dist/graders/types.js +2 -0
  42. package/dist/graders/types.js.map +1 -0
  43. package/dist/index.d.ts +8 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +9 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/report.d.ts +39 -0
  48. package/dist/report.d.ts.map +1 -0
  49. package/dist/report.js +120 -0
  50. package/dist/report.js.map +1 -0
  51. package/dist/runner.d.ts +59 -0
  52. package/dist/runner.d.ts.map +1 -0
  53. package/dist/runner.js +217 -0
  54. package/dist/runner.js.map +1 -0
  55. package/dist/tasks/edit.remove-section.d.ts +15 -0
  56. package/dist/tasks/edit.remove-section.d.ts.map +1 -0
  57. package/dist/tasks/edit.remove-section.js +31 -0
  58. package/dist/tasks/edit.remove-section.js.map +1 -0
  59. package/dist/tasks/edit.rename-symbol.d.ts +16 -0
  60. package/dist/tasks/edit.rename-symbol.d.ts.map +1 -0
  61. package/dist/tasks/edit.rename-symbol.js +34 -0
  62. package/dist/tasks/edit.rename-symbol.js.map +1 -0
  63. package/dist/tasks/edit.replace-greeting.d.ts +16 -0
  64. package/dist/tasks/edit.replace-greeting.d.ts.map +1 -0
  65. package/dist/tasks/edit.replace-greeting.js +29 -0
  66. package/dist/tasks/edit.replace-greeting.js.map +1 -0
  67. package/dist/tasks/edit.write-hello.d.ts +15 -0
  68. package/dist/tasks/edit.write-hello.d.ts.map +1 -0
  69. package/dist/tasks/edit.write-hello.js +22 -0
  70. package/dist/tasks/edit.write-hello.js.map +1 -0
  71. package/dist/tasks/index.d.ts +9 -0
  72. package/dist/tasks/index.d.ts.map +1 -0
  73. package/dist/tasks/index.js +37 -0
  74. package/dist/tasks/index.js.map +1 -0
  75. package/dist/tasks/memory.recall-relevant.d.ts +19 -0
  76. package/dist/tasks/memory.recall-relevant.d.ts.map +1 -0
  77. package/dist/tasks/memory.recall-relevant.js +36 -0
  78. package/dist/tasks/memory.recall-relevant.js.map +1 -0
  79. package/dist/tasks/multi.refactor-move.d.ts +16 -0
  80. package/dist/tasks/multi.refactor-move.d.ts.map +1 -0
  81. package/dist/tasks/multi.refactor-move.js +37 -0
  82. package/dist/tasks/multi.refactor-move.js.map +1 -0
  83. package/dist/tasks/multi.run-and-report.d.ts +16 -0
  84. package/dist/tasks/multi.run-and-report.d.ts.map +1 -0
  85. package/dist/tasks/multi.run-and-report.js +26 -0
  86. package/dist/tasks/multi.run-and-report.js.map +1 -0
  87. package/dist/tasks/multi.summarize.d.ts +16 -0
  88. package/dist/tasks/multi.summarize.d.ts.map +1 -0
  89. package/dist/tasks/multi.summarize.js +35 -0
  90. package/dist/tasks/multi.summarize.js.map +1 -0
  91. package/dist/tasks/read.list-files.d.ts +15 -0
  92. package/dist/tasks/read.list-files.d.ts.map +1 -0
  93. package/dist/tasks/read.list-files.js +28 -0
  94. package/dist/tasks/read.list-files.js.map +1 -0
  95. package/dist/tasks/read.package-version.d.ts +15 -0
  96. package/dist/tasks/read.package-version.d.ts.map +1 -0
  97. package/dist/tasks/read.package-version.js +25 -0
  98. package/dist/tasks/read.package-version.js.map +1 -0
  99. package/dist/tasks/read.search-todos.d.ts +16 -0
  100. package/dist/tasks/read.search-todos.d.ts.map +1 -0
  101. package/dist/tasks/read.search-todos.js +30 -0
  102. package/dist/tasks/read.search-todos.js.map +1 -0
  103. package/package.json +57 -3
@@ -0,0 +1,157 @@
1
+ import { loadSchemaFile } from '@ikarmic/forge-core';
2
+ /**
3
+ * Grader that parses `finalText` as JSON and validates it against the
4
+ * supplied schema. Returns `{ passed: true }` on a successful
5
+ * validation, `{ passed: false, details }` with the validation error
6
+ * + truncated text otherwise.
7
+ *
8
+ * ```ts
9
+ * import { z } from 'zod';
10
+ * import { jsonSchema } from '@ikarmic/forge-eval';
11
+ *
12
+ * const prSchema = z.object({
13
+ * title: z.string(),
14
+ * body: z.string().min(20),
15
+ * });
16
+ *
17
+ * const task = defineTask({
18
+ * id: 'summarize-pr',
19
+ * graders: [jsonSchema(prSchema)],
20
+ * ...
21
+ * });
22
+ *
23
+ * // Or load the same schema the agent uses via --schema:
24
+ * const task = defineTask({
25
+ * id: 'extract-pr',
26
+ * graders: [jsonSchema('./schemas/pr-summary.ts')],
27
+ * ...
28
+ * });
29
+ * ```
30
+ */
31
+ export function jsonSchema(schema, options = {}) {
32
+ const maxDetailChars = options.maxDetailChars ?? 400;
33
+ if (typeof schema === 'string' && options.schemaIsPath === false) {
34
+ throw new Error('jsonSchema: schema was a string but schemaIsPath is false: string schemas are always loaded as a file path.');
35
+ }
36
+ // Resolved lazily (loading a path requires a dynamic import, which is
37
+ // async) and cached across grader invocations. When `schema` is already
38
+ // a Zod schema object, `resolved` is set up-front and the grader stays
39
+ // fully synchronous: no behavior change for existing callers.
40
+ let resolved = typeof schema === 'string' ? undefined : schema;
41
+ let loadError;
42
+ return (ctx) => {
43
+ if (resolved !== undefined) {
44
+ return gradeAgainstSchema(resolved, ctx, maxDetailChars);
45
+ }
46
+ if (loadError !== undefined) {
47
+ return { passed: false, message: 'failed to load schema file', details: loadError };
48
+ }
49
+ return loadSchemaFile(schema).then((s) => {
50
+ resolved = s;
51
+ return gradeAgainstSchema(s, ctx, maxDetailChars);
52
+ }, (err) => {
53
+ loadError = err.message;
54
+ return { passed: false, message: 'failed to load schema file', details: loadError };
55
+ });
56
+ };
57
+ }
58
+ function gradeAgainstSchema(zodSchema, ctx, maxDetailChars) {
59
+ const text = ctx.result.finalText ?? '';
60
+ const parsed = tryParseJson(text);
61
+ if (parsed.parseError) {
62
+ return {
63
+ passed: false,
64
+ message: 'finalText is not valid JSON',
65
+ details: `${parsed.parseError}\n\ntext (first ${maxDetailChars} chars):\n${truncate(text, maxDetailChars)}`,
66
+ };
67
+ }
68
+ const result = zodSchema.safeParse(parsed.value);
69
+ if (result.success) {
70
+ return { passed: true, message: 'JSON schema matched' };
71
+ }
72
+ return {
73
+ passed: false,
74
+ message: 'JSON schema mismatch',
75
+ details: formatZodError(result.error, maxDetailChars, text),
76
+ };
77
+ }
78
+ /**
79
+ * Grader that validates the parsed JSON's *subset* of fields: useful
80
+ * when the agent may add extra fields you don't want to grade but
81
+ * the core fields must match. Behaves like {@link jsonSchema} but
82
+ * wraps the user schema in `passthrough()` before validating, so any
83
+ * extra fields are ignored rather than triggering a strict failure.
84
+ *
85
+ * Note: when `schema` is a path, it can't be inspected synchronously,
86
+ * so the `passthrough()` wrapping is only applied to a Zod schema
87
+ * object passed directly: a path-loaded schema is graded as-is.
88
+ */
89
+ export function jsonSchemaPartial(schema, options = {}) {
90
+ // `passthrough()` keeps the schema's own type but ignores unknown
91
+ // keys. For object schemas this means extra fields don't fail;
92
+ // for non-object schemas it's a no-op. `passthrough` is only on
93
+ // ZodObject, so we duck-type-check.
94
+ const obj = schema;
95
+ const tolerant = typeof obj.passthrough === 'function'
96
+ ? obj.passthrough()
97
+ : schema;
98
+ return jsonSchema(tolerant, options);
99
+ }
100
+ /**
101
+ * Try to parse `text` as JSON. Falls back to extracting the content
102
+ * of a single ```json ... ``` (or bare ``` ... ```) fenced block.
103
+ * Mirrors `validateFinalText` from `@ikarmic/forge-core`'s structured
104
+ * module: duplicated here so this leaf package doesn't pull in core.
105
+ */
106
+ function tryParseJson(text) {
107
+ const trimmed = text.trim();
108
+ if (trimmed.length === 0) {
109
+ return { value: undefined, parseError: 'Response was empty' };
110
+ }
111
+ // Try raw text first.
112
+ try {
113
+ return { value: JSON.parse(trimmed), parseError: null };
114
+ }
115
+ catch {
116
+ // Try a single fenced block.
117
+ }
118
+ const fence = extractFencedJson(trimmed);
119
+ if (fence !== null) {
120
+ try {
121
+ return { value: JSON.parse(fence), parseError: null };
122
+ }
123
+ catch (err) {
124
+ return { value: undefined, parseError: `Found a json fence but its contents are not valid JSON: ${err.message}` };
125
+ }
126
+ }
127
+ return {
128
+ value: undefined,
129
+ parseError: 'Response is not valid JSON (and contains no ```json fence)',
130
+ };
131
+ }
132
+ function extractFencedJson(text) {
133
+ const m = text.match(/```(?:json)?\s*([\s\S]*?)```/);
134
+ if (m && typeof m[1] === 'string')
135
+ return m[1].trim();
136
+ return null;
137
+ }
138
+ /**
139
+ * Render a ZodError as a one-issue-per-line summary plus a truncated
140
+ * version of the offending text. Designed for the report view, not
141
+ * the model: humans read this.
142
+ */
143
+ function formatZodError(err, maxDetailChars, originalText) {
144
+ const lines = err.issues
145
+ .map((issue) => {
146
+ const path = issue.path.length > 0 ? issue.path.join('.') : '(root)';
147
+ return ` - ${path}: ${issue.message}`;
148
+ })
149
+ .join('\n');
150
+ return `Validation errors:\n${lines}\n\ntext (first ${maxDetailChars} chars):\n${truncate(originalText, maxDetailChars)}`;
151
+ }
152
+ function truncate(s, max) {
153
+ if (s.length <= max)
154
+ return s;
155
+ return s.slice(0, max) + '…';
156
+ }
157
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/graders/schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import type { Grader } from './types.js';
2
+ /** Options for {@link commandRuns}. */
3
+ export interface CommandRunsOptions {
4
+ /**
5
+ * The command to run, as a string (parsed with `shell: true`) or as
6
+ * `[program, ...args]` for direct execution. Strings are easier for
7
+ * shell pipelines; arrays are safer (no shell interpolation).
8
+ */
9
+ command: string | readonly string[];
10
+ /** Wall-clock cap in ms. Default 30s. */
11
+ timeoutMs?: number;
12
+ /**
13
+ * Optional substring or regex the command's stdout must match. The command
14
+ * must still exit 0: this is an *additional* check.
15
+ */
16
+ contains?: string;
17
+ /** Optional regex for stdout. */
18
+ matches?: RegExp;
19
+ /** When true, check stderr instead of stdout for `contains` / `matches`. */
20
+ fromStderr?: boolean;
21
+ /** Additional env vars to set for the command. */
22
+ env?: Record<string, string>;
23
+ }
24
+ /**
25
+ * Grader that runs a shell command in the task's cwd and passes when the
26
+ * command exits 0 (and optionally matches a stdout/stderr predicate).
27
+ *
28
+ * Use this for tasks like "run the test suite" or "execute the script and
29
+ * report exit code" where the side effect itself is the thing being graded.
30
+ *
31
+ * Cross-platform note: shell strings use `cmd.exe` on Windows and `sh`
32
+ * elsewhere. For Windows-friendly commands prefer `node -e "..."` or a
33
+ * `[program, ...args]` array.
34
+ */
35
+ export declare function commandRuns(options: CommandRunsOptions): Grader;
36
+ //# sourceMappingURL=shell.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell.d.ts","sourceRoot":"","sources":["../../src/graders/shell.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAA+B,MAAM,YAAY,CAAC;AAItE,uCAAuC;AACvC,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,OAAO,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC;IACpC,yCAAyC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iCAAiC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,kDAAkD;IAClD,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,CAkC/D"}
@@ -0,0 +1,72 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { promisify } from 'node:util';
3
+ import { resolve } from 'node:path';
4
+ const execFileAsync = promisify(execFile);
5
+ /**
6
+ * Grader that runs a shell command in the task's cwd and passes when the
7
+ * command exits 0 (and optionally matches a stdout/stderr predicate).
8
+ *
9
+ * Use this for tasks like "run the test suite" or "execute the script and
10
+ * report exit code" where the side effect itself is the thing being graded.
11
+ *
12
+ * Cross-platform note: shell strings use `cmd.exe` on Windows and `sh`
13
+ * elsewhere. For Windows-friendly commands prefer `node -e "..."` or a
14
+ * `[program, ...args]` array.
15
+ */
16
+ export function commandRuns(options) {
17
+ const timeoutMs = options.timeoutMs ?? 30_000;
18
+ return async (ctx) => {
19
+ const cwd = resolve(ctx.cwd);
20
+ try {
21
+ const { stdout, stderr } = await runCommand(options.command, cwd, timeoutMs, options.env);
22
+ const stream = options.fromStderr ? stderr : stdout;
23
+ if (options.contains !== undefined && !stream.includes(options.contains)) {
24
+ return {
25
+ passed: false,
26
+ message: `command ran but output missing "${options.contains}"`,
27
+ details: truncate(stream),
28
+ };
29
+ }
30
+ if (options.matches && !options.matches.test(stream)) {
31
+ return {
32
+ passed: false,
33
+ message: `command ran but output did not match ${options.matches}`,
34
+ details: truncate(stream),
35
+ };
36
+ }
37
+ return {
38
+ passed: true,
39
+ message: `command ok: ${summarize(options.command)}`,
40
+ };
41
+ }
42
+ catch (err) {
43
+ const message = err instanceof Error ? err.message : String(err);
44
+ return {
45
+ passed: false,
46
+ message: `command failed: ${summarize(options.command)}`,
47
+ details: message,
48
+ };
49
+ }
50
+ };
51
+ }
52
+ async function runCommand(command, cwd, timeoutMs, extraEnv) {
53
+ const env = { ...process.env, ...(extraEnv ?? {}) };
54
+ if (typeof command === 'string') {
55
+ // Use the platform default shell so users can write shell idioms
56
+ // (pipelines, redirection, etc.). shell-quoting is the caller's job.
57
+ return execFileAsync(command, { cwd, timeout: timeoutMs, env, shell: true, maxBuffer: 4 * 1024 * 1024 });
58
+ }
59
+ const [program, ...args] = command;
60
+ if (!program)
61
+ throw new Error('commandRuns: empty command array');
62
+ return execFileAsync(program, args, { cwd, timeout: timeoutMs, env, maxBuffer: 4 * 1024 * 1024 });
63
+ }
64
+ function summarize(cmd) {
65
+ return typeof cmd === 'string' ? cmd : cmd.join(' ');
66
+ }
67
+ function truncate(s, max = 240) {
68
+ if (s.length <= max)
69
+ return s;
70
+ return s.slice(0, max) + '…';
71
+ }
72
+ //# sourceMappingURL=shell.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell.js","sourceRoot":"","sources":["../../src/graders/shell.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { Grader } from './types.js';
2
+ /** Options for {@link regex}. */
3
+ export interface RegexGraderOptions {
4
+ /** Match flags. Default: none. 'i' for case-insensitive. */
5
+ flags?: string;
6
+ /**
7
+ * When true (default), treat `result.finalText` as multiline so `^` / `$`
8
+ * match line boundaries. Useful when the model emits bulleted answers.
9
+ */
10
+ multiline?: boolean;
11
+ }
12
+ /**
13
+ * Grader that passes when {@link AgentRunResult.finalText} matches a regex.
14
+ *
15
+ * ```ts
16
+ * graders: [regex(/version.*?\d+\.\d+\.\d+/i)]
17
+ * ```
18
+ */
19
+ export declare function regex(pattern: RegExp, options?: RegexGraderOptions): Grader;
20
+ /** Grader that passes when `finalText` includes a substring (case-sensitive). */
21
+ export declare function contains(substring: string): Grader;
22
+ /**
23
+ * Grader that passes when `finalText.trim()` exactly equals `expected.trim()`.
24
+ * Use this for tasks where the answer is deterministic (e.g. the agent is
25
+ * supposed to read a single file and report a single value).
26
+ */
27
+ export declare function equals(expected: string): Grader;
28
+ //# sourceMappingURL=text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../src/graders/text.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAA+B,MAAM,YAAY,CAAC;AAEtE,iCAAiC;AACjC,MAAM,WAAW,kBAAkB;IACjC,4DAA4D;IAC5D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;GAMG;AACH,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAuB,GAAG,MAAM,CAc/E;AAED,iFAAiF;AACjF,wBAAgB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAOlD;AAED;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAY/C"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Grader that passes when {@link AgentRunResult.finalText} matches a regex.
3
+ *
4
+ * ```ts
5
+ * graders: [regex(/version.*?\d+\.\d+\.\d+/i)]
6
+ * ```
7
+ */
8
+ export function regex(pattern, options = {}) {
9
+ const { flags = '', multiline = true } = options;
10
+ const merged = mergeFlags(pattern, flags, multiline);
11
+ return (_ctx) => {
12
+ const text = _ctx.result.finalText ?? '';
13
+ const matched = merged.test(text);
14
+ return matched
15
+ ? { passed: true, message: `regex ${merged} matched` }
16
+ : {
17
+ passed: false,
18
+ message: `regex ${merged} did not match`,
19
+ details: truncate(text),
20
+ };
21
+ };
22
+ }
23
+ /** Grader that passes when `finalText` includes a substring (case-sensitive). */
24
+ export function contains(substring) {
25
+ return (ctx) => {
26
+ const text = ctx.result.finalText ?? '';
27
+ return text.includes(substring)
28
+ ? { passed: true, message: `contains "${substring}"` }
29
+ : { passed: false, message: `does not contain "${substring}"`, details: truncate(text) };
30
+ };
31
+ }
32
+ /**
33
+ * Grader that passes when `finalText.trim()` exactly equals `expected.trim()`.
34
+ * Use this for tasks where the answer is deterministic (e.g. the agent is
35
+ * supposed to read a single file and report a single value).
36
+ */
37
+ export function equals(expected) {
38
+ return (ctx) => {
39
+ const actual = (ctx.result.finalText ?? '').trim();
40
+ const want = expected.trim();
41
+ return actual === want
42
+ ? { passed: true, message: `equals "${want}"` }
43
+ : {
44
+ passed: false,
45
+ message: `text mismatch`,
46
+ details: `expected: ${JSON.stringify(want)}\nactual: ${JSON.stringify(actual)}`,
47
+ };
48
+ };
49
+ }
50
+ /**
51
+ * Merge new flags with an existing RegExp's flags, deduplicating. Order doesn't
52
+ * matter for the regex engine; we just need to not pass `g/.../g` which would
53
+ * change `test()` to stateful behaviour.
54
+ */
55
+ function mergeFlags(src, extra, multiline) {
56
+ const set = new Set(src.flags.split(''));
57
+ for (const c of extra)
58
+ set.add(c);
59
+ if (multiline)
60
+ set.add('m');
61
+ // `g` would make `.test()` stateful across graders: strip it.
62
+ set.delete('g');
63
+ return new RegExp(src.source, Array.from(set).join(''));
64
+ }
65
+ function truncate(s, max = 240) {
66
+ if (s.length <= max)
67
+ return s;
68
+ return s.slice(0, max) + '…';
69
+ }
70
+ //# sourceMappingURL=text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/graders/text.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,81 @@
1
+ import type { AgentRunResult } from '@ikarmic/forge-core';
2
+ /**
3
+ * One tool invocation captured during a task run. Built up from the agent's
4
+ * `tool_call` + `tool_result` events, correlated by id, so graders can inspect
5
+ * what the model actually did (not just what it said).
6
+ */
7
+ export interface ToolInvocation {
8
+ /** Tool name as exposed to the model (e.g. "read_file", "edit_file"). */
9
+ name: string;
10
+ /** Raw arguments the model passed. */
11
+ args: unknown;
12
+ /** Tool's result (after redaction), or the error message if `isError` is true. */
13
+ result: unknown;
14
+ /** True when the tool threw or returned an error. */
15
+ isError: boolean;
16
+ }
17
+ /**
18
+ * The context a grader runs in. Everything a grader might need to make a
19
+ * verdict: where the task ran, what the model said, what tools it called,
20
+ * the original task description.
21
+ */
22
+ export interface GraderContext {
23
+ /** Absolute path to the task's isolated working directory. */
24
+ cwd: string;
25
+ /** The task that was just run (in case the grader wants metadata). */
26
+ task: TaskInfo;
27
+ /** The agent's run result: finalText, iterations, tokens, etc. */
28
+ result: AgentRunResult;
29
+ /** Ordered list of every tool the agent invoked, with args + results. */
30
+ toolInvocations: ToolInvocation[];
31
+ }
32
+ /**
33
+ * Lightweight task descriptor surfaced to graders. Full task defs include
34
+ * the `setup` function which isn't relevant to grading.
35
+ */
36
+ export interface TaskInfo {
37
+ id: string;
38
+ name: string;
39
+ category: TaskCategory;
40
+ description: string;
41
+ }
42
+ export type TaskCategory = 'read' | 'edit' | 'multi-step';
43
+ /** What a grader returns. `passed` drives the score; `message` shows in the report. */
44
+ export interface GraderResult {
45
+ passed: boolean;
46
+ /** Short label for the report ("regex matched", "file exists", ...). */
47
+ message: string;
48
+ /** Optional longer explanation when failing: included in the markdown report. */
49
+ details?: string;
50
+ }
51
+ /**
52
+ * A grader is just an async function. Sync return is wrapped automatically.
53
+ */
54
+ export type Grader = (ctx: GraderContext) => Promise<GraderResult> | GraderResult;
55
+ /**
56
+ * Internal type used by `defineTask`: keeps the grader list type-safe while
57
+ * allowing setup/task to be optional in user code.
58
+ */
59
+ export interface TaskDefinition {
60
+ id: string;
61
+ name: string;
62
+ category: TaskCategory;
63
+ description: string;
64
+ /** The user prompt given to the agent. */
65
+ task: string;
66
+ /**
67
+ * Optional setup: writes fixture files into the task's cwd before the agent
68
+ * starts. The cwd is a fresh temp directory per run.
69
+ */
70
+ setup?: (cwd: string) => Promise<void> | void;
71
+ /**
72
+ * Run with project memory enabled. Default off: memory would add noise to the other tasks.
73
+ * The user's global memory is hidden for these runs so the result does not depend on the host.
74
+ */
75
+ memory?: boolean;
76
+ /** Graders run after the agent finishes. All must pass for the task to pass. */
77
+ graders: Grader[];
78
+ /** Optional tags for filtering (e.g. "windows", "needs-network"). */
79
+ tags?: string[];
80
+ }
81
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/graders/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb,sCAAsC;IACtC,IAAI,EAAE,OAAO,CAAC;IACd,kFAAkF;IAClF,MAAM,EAAE,OAAO,CAAC;IAChB,qDAAqD;IACrD,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,8DAA8D;IAC9D,GAAG,EAAE,MAAM,CAAC;IACZ,sEAAsE;IACtE,IAAI,EAAE,QAAQ,CAAC;IACf,kEAAkE;IAClE,MAAM,EAAE,cAAc,CAAC;IACvB,yEAAyE;IACzE,eAAe,EAAE,cAAc,EAAE,CAAC;CACnC;AAED;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,YAAY,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,YAAY,CAAC;AAE1D,uFAAuF;AACvF,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,OAAO,CAAC;IAChB,wEAAwE;IACxE,OAAO,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY,CAAC;AAElF;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,YAAY,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC9C;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,gFAAgF;IAChF,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/graders/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,8 @@
1
+ export { regex, contains, equals, fileExists, fileMatches, fileMissing, directoryHas, commandRuns, toolWasCalled, toolNotCalled, finalTextNonEmpty, completed, defineTask, } from './graders/index.js';
2
+ export type { Grader, GraderContext, GraderResult, TaskCategory, TaskDefinition, TaskInfo, ToolInvocation, RegexGraderOptions, CommandRunsOptions, } from './graders/index.js';
3
+ export { TASKS, findTask } from './tasks/index.js';
4
+ export { runTask, runSuite, resolveModel } from './runner.js';
5
+ export type { TaskRunResult, SuiteRunResult, RunTaskOptions } from './runner.js';
6
+ export { formatJsonReport, formatMarkdownReport, formatTerminalSummary } from './report.js';
7
+ export type { JsonReport } from './report.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,EACL,QAAQ,EACR,MAAM,EACN,UAAU,EACV,WAAW,EACX,WAAW,EACX,YAAY,EACZ,WAAW,EACX,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,SAAS,EACT,UAAU,GACX,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,MAAM,EACN,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,QAAQ,EACR,cAAc,EACd,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAGnD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC9D,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAGjF,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAC5F,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,9 @@
1
+ // Graders
2
+ export { regex, contains, equals, fileExists, fileMatches, fileMissing, directoryHas, commandRuns, toolWasCalled, toolNotCalled, finalTextNonEmpty, completed, defineTask, } from './graders/index.js';
3
+ // Tasks
4
+ export { TASKS, findTask } from './tasks/index.js';
5
+ // Runner
6
+ export { runTask, runSuite, resolveModel } from './runner.js';
7
+ // Report
8
+ export { formatJsonReport, formatMarkdownReport, formatTerminalSummary } from './report.js';
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,UAAU;AACV,OAAO,EACL,KAAK,EACL,QAAQ,EACR,MAAM,EACN,UAAU,EACV,WAAW,EACX,WAAW,EACX,YAAY,EACZ,WAAW,EACX,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,SAAS,EACT,UAAU,GACX,MAAM,oBAAoB,CAAC;AAa5B,QAAQ;AACR,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEnD,SAAS;AACT,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG9D,SAAS;AACT,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,39 @@
1
+ import type { SuiteRunResult, TaskRunResult } from './runner.js';
2
+ /** Render a human-friendly markdown table for a suite run. */
3
+ export declare function formatMarkdownReport(suite: SuiteRunResult): string;
4
+ /** Render a compact single-line summary for the terminal. */
5
+ export declare function formatTerminalSummary(suite: SuiteRunResult): string;
6
+ /** JSON shape: stable, machine-readable, includes everything graders saw. */
7
+ export interface JsonReport {
8
+ model: {
9
+ provider: string;
10
+ model: string;
11
+ };
12
+ startedAt: string;
13
+ finishedAt: string;
14
+ summary: SuiteRunResult['summary'];
15
+ tasks: Array<{
16
+ id: string;
17
+ name: string;
18
+ category: string;
19
+ passed: boolean;
20
+ durationMs: number;
21
+ iterations: number;
22
+ reason: string;
23
+ graderResults: Array<{
24
+ passed: boolean;
25
+ message: string;
26
+ details?: string;
27
+ }>;
28
+ toolInvocations: Array<{
29
+ name: string;
30
+ args: unknown;
31
+ isError: boolean;
32
+ }>;
33
+ finalText: string;
34
+ error?: string;
35
+ }>;
36
+ }
37
+ export declare function formatJsonReport(suite: SuiteRunResult): JsonReport;
38
+ export type { TaskRunResult };
39
+ //# sourceMappingURL=report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAOjE,8DAA8D;AAC9D,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAoElE;AAED,6DAA6D;AAC7D,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAenE;AAED,6EAA6E;AAC7E,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,cAAc,CAAC,SAAS,CAAC,CAAC;IACnC,KAAK,EAAE,KAAK,CAAC;QACX,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,OAAO,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;QACf,aAAa,EAAE,KAAK,CAAC;YAAE,MAAM,EAAE,OAAO,CAAC;YAAC,OAAO,EAAE,MAAM,CAAC;YAAC,OAAO,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAC7E,eAAe,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,OAAO,CAAC;YAAC,OAAO,EAAE,OAAO,CAAA;SAAE,CAAC,CAAC;QAC1E,SAAS,EAAE,MAAM,CAAC;QAClB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC,CAAC;CACJ;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,cAAc,GAAG,UAAU,CAwBlE;AAaD,YAAY,EAAE,aAAa,EAAE,CAAC"}