@cydm/pie 2.6.5 → 2.6.7
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/builtin/extensions/ask-user/index.js +3 -3
- package/dist/builtin/extensions/mcp-adapter/index.js +141 -31
- package/dist/builtin/extensions/plan-mode/index.js +3 -3
- package/dist/builtin/extensions/subagent/index.js +362 -6
- package/dist/builtin/extensions/todo/index.js +3 -3
- package/dist/builtin/skills/chrome-devtools-axi/chrome-devtools-axi-bridge.js +3 -2
- package/dist/builtin/skills/chrome-devtools-axi/chrome-devtools-axi-runtime.js +1 -1
- package/dist/builtin/skills/chrome-devtools-axi/{chunk-UPATXALW.js → chunk-U75F4DPF.js} +60 -0
- package/dist/builtin/skills/chrome-devtools-axi/{cli-5Z4COIKQ.js → cli-4ITIR57L.js} +85 -36
- package/dist/builtin/skills/skill-creator/SKILL.md +7 -8
- package/dist/chunks/{chunk-5OXH6NUH.js → chunk-7B4IIBVS.js} +307 -6
- package/dist/chunks/{chunk-AETQBDEG.js → chunk-PAC62XU4.js} +1 -1
- package/dist/chunks/{chunk-QKSK5K5N.js → chunk-T6GMEDIE.js} +1207 -225
- package/dist/chunks/{chunk-TFRQE7UQ.js → chunk-VUKF7U7Q.js} +1 -1
- package/dist/chunks/{src-Z4KWMX6E.js → src-HPIBCE2I.js} +2 -2
- package/dist/chunks/{test-stream-3FG7FHHU.js → test-stream-Y7WXELAJ.js} +1 -1
- package/dist/cli.js +2619 -2510
- package/package.json +2 -2
|
@@ -4,10 +4,11 @@ import {
|
|
|
4
4
|
BRIDGE_PORT_IN_USE_EXIT_CODE,
|
|
5
5
|
PAGE_IDENTITY_CHANGED_ERROR,
|
|
6
6
|
clearSelectedPageId,
|
|
7
|
+
readSelfStartTime,
|
|
7
8
|
resolveSessionName,
|
|
8
9
|
resolveSessionPidFile,
|
|
9
10
|
resolveSessionPort
|
|
10
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-U75F4DPF.js";
|
|
11
12
|
import {
|
|
12
13
|
__commonJS,
|
|
13
14
|
__export,
|
|
@@ -19599,7 +19600,7 @@ async function isBridgeTargetReachable(client) {
|
|
|
19599
19600
|
function writePidFile(port) {
|
|
19600
19601
|
const pidFile = resolveSessionPidFile();
|
|
19601
19602
|
mkdirSync(dirname(pidFile), { recursive: true });
|
|
19602
|
-
writeFileSync(pidFile, JSON.stringify({ pid: process.pid, port }));
|
|
19603
|
+
writeFileSync(pidFile, JSON.stringify({ pid: process.pid, port, startTime: readSelfStartTime() }));
|
|
19603
19604
|
}
|
|
19604
19605
|
function removePidFile(pidFile = resolveSessionPidFile(), ownerPid = process.pid) {
|
|
19605
19606
|
try {
|
|
@@ -21,6 +21,6 @@ function tryFastPath(argv, options) {
|
|
|
21
21
|
|
|
22
22
|
// vendor/chrome-devtools-axi/bin/chrome-devtools-axi.ts
|
|
23
23
|
if (!tryFastPath(process.argv.slice(2), { version: VERSION })) {
|
|
24
|
-
const { main } = await import("./cli-
|
|
24
|
+
const { main } = await import("./cli-4ITIR57L.js");
|
|
25
25
|
await main(process.argv.slice(2));
|
|
26
26
|
}
|
|
@@ -200,10 +200,70 @@ function resolveBridgeScript(importMetaDir) {
|
|
|
200
200
|
var BRIDGE_PORT_IN_USE_EXIT_CODE = 48;
|
|
201
201
|
var PAGE_IDENTITY_CHANGED_ERROR = "The browser reconnected and every page id changed, so this call did not target the page you selected";
|
|
202
202
|
|
|
203
|
+
// vendor/chrome-devtools-axi/src/process-identity.ts
|
|
204
|
+
import { execFileSync } from "node:child_process";
|
|
205
|
+
function inspectProcessIdentity(pid) {
|
|
206
|
+
if (!Number.isInteger(pid) || pid <= 0) return {};
|
|
207
|
+
if (process.platform === "win32") {
|
|
208
|
+
try {
|
|
209
|
+
const output = execFileSync(
|
|
210
|
+
"powershell",
|
|
211
|
+
[
|
|
212
|
+
"-NoProfile",
|
|
213
|
+
"-NonInteractive",
|
|
214
|
+
"-Command",
|
|
215
|
+
`$p = Get-CimInstance Win32_Process -Filter "ProcessId=<pid>"; if ($p) { $p.CommandLine; $p.CreationDate.ToString('o') }`.replace("<pid>", String(pid))
|
|
216
|
+
],
|
|
217
|
+
{ encoding: "utf-8", timeout: 4e3 }
|
|
218
|
+
);
|
|
219
|
+
const lines = output.split(/\r?\n/).filter((line) => line.length > 0);
|
|
220
|
+
if (lines.length === 0) return {};
|
|
221
|
+
const startTime = lines.length >= 2 ? lines[lines.length - 1] : void 0;
|
|
222
|
+
return { command: lines.slice(0, lines.length - 1).join("\n"), startTime };
|
|
223
|
+
} catch {
|
|
224
|
+
return {};
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
try {
|
|
228
|
+
const psEnv = { ...process.env, LC_ALL: "C", LANG: "C" };
|
|
229
|
+
const output = execFileSync(
|
|
230
|
+
"ps",
|
|
231
|
+
["-p", String(pid), "-o", "lstart=", "-o", "command="],
|
|
232
|
+
{ encoding: "utf-8", timeout: 1e3, env: psEnv }
|
|
233
|
+
);
|
|
234
|
+
const firstNewline = output.indexOf("\n");
|
|
235
|
+
const firstLine = firstNewline === -1 ? output : output.slice(0, firstNewline);
|
|
236
|
+
const lstart = /^(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s+(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+\d{1,2}\s+\d{1,2}:\d{2}:\d{2}\s+\d{4}\s+/.exec(firstLine);
|
|
237
|
+
if (lstart) {
|
|
238
|
+
return { startTime: lstart[0].trimEnd(), command: output.slice(lstart[0].length) };
|
|
239
|
+
}
|
|
240
|
+
try {
|
|
241
|
+
const command = execFileSync("ps", ["-p", String(pid), "-o", "command="], {
|
|
242
|
+
encoding: "utf-8",
|
|
243
|
+
timeout: 1e3,
|
|
244
|
+
env: psEnv
|
|
245
|
+
});
|
|
246
|
+
return { command };
|
|
247
|
+
} catch {
|
|
248
|
+
return {};
|
|
249
|
+
}
|
|
250
|
+
} catch {
|
|
251
|
+
return {};
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
function readProcessStartTime(pid) {
|
|
255
|
+
return inspectProcessIdentity(pid).startTime;
|
|
256
|
+
}
|
|
257
|
+
function readSelfStartTime() {
|
|
258
|
+
return readProcessStartTime(process.pid);
|
|
259
|
+
}
|
|
260
|
+
|
|
203
261
|
export {
|
|
204
262
|
resolveBridgeScript,
|
|
205
263
|
BRIDGE_PORT_IN_USE_EXIT_CODE,
|
|
206
264
|
PAGE_IDENTITY_CHANGED_ERROR,
|
|
265
|
+
inspectProcessIdentity,
|
|
266
|
+
readSelfStartTime,
|
|
207
267
|
resolveSessionName,
|
|
208
268
|
resolveSessionPort,
|
|
209
269
|
resolveSessionStateDir,
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
PAGE_IDENTITY_CHANGED_ERROR,
|
|
8
8
|
clearSelectedPageId,
|
|
9
9
|
getSelectedPageId,
|
|
10
|
+
inspectProcessIdentity,
|
|
10
11
|
overlaySessionSelected,
|
|
11
12
|
rememberToolRouting,
|
|
12
13
|
resolveBridgeScript,
|
|
@@ -14,7 +15,7 @@ import {
|
|
|
14
15
|
resolveSessionPidFile,
|
|
15
16
|
resolveSessionPort,
|
|
16
17
|
resolveSessionStateDir
|
|
17
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-U75F4DPF.js";
|
|
18
19
|
import "./chunk-OJ6N23UZ.js";
|
|
19
20
|
|
|
20
21
|
// ../../node_modules/chrome-devtools-axi/node_modules/@toon-format/toon/dist/index.mjs
|
|
@@ -1964,42 +1965,79 @@ function commandLineLooksLikeBridge(command) {
|
|
|
1964
1965
|
const tokens = splitCommandLine(command);
|
|
1965
1966
|
if (tokens.length === 0) return false;
|
|
1966
1967
|
if (!/(?:^|[\\/])(node|npx|tsx)(?:\.(?:exe|cmd))?$/i.test(tokens[0])) return false;
|
|
1968
|
+
const operandOptions = /* @__PURE__ */ new Set([
|
|
1969
|
+
"--require",
|
|
1970
|
+
"-r",
|
|
1971
|
+
"--import",
|
|
1972
|
+
"--loader",
|
|
1973
|
+
"--experimental-loader",
|
|
1974
|
+
"--conditions",
|
|
1975
|
+
"-C",
|
|
1976
|
+
"--inspect-port",
|
|
1977
|
+
"--title",
|
|
1978
|
+
"--watch-path",
|
|
1979
|
+
"--max-old-space-size",
|
|
1980
|
+
"--max-semi-space-size"
|
|
1981
|
+
]);
|
|
1982
|
+
let optionsEnded = false;
|
|
1983
|
+
const npxRunner = /(?:^|[\\/])npx(?:\.(?:exe|cmd))?$/i.test(tokens[0]);
|
|
1984
|
+
let loaderSeen = false;
|
|
1967
1985
|
for (let index = 1; index < tokens.length; index++) {
|
|
1968
1986
|
const token = tokens[index];
|
|
1969
|
-
if (token
|
|
1970
|
-
|
|
1987
|
+
if (!optionsEnded && token === "--") {
|
|
1988
|
+
optionsEnded = true;
|
|
1989
|
+
continue;
|
|
1990
|
+
}
|
|
1991
|
+
if (!optionsEnded && token.startsWith("-")) {
|
|
1992
|
+
const option = token.split("=", 1)[0];
|
|
1993
|
+
if (["-e", "--eval", "-p", "--print"].includes(option)) return false;
|
|
1994
|
+
if (!token.includes("=") && operandOptions.has(option)) index++;
|
|
1995
|
+
continue;
|
|
1996
|
+
}
|
|
1997
|
+
if (npxRunner && !loaderSeen && /(?:^|[\\/])tsx(?:\.(?:exe|cmd))?$/i.test(token)) {
|
|
1998
|
+
loaderSeen = true;
|
|
1999
|
+
continue;
|
|
2000
|
+
}
|
|
1971
2001
|
const base = token.split(/[\\/]/).pop() ?? token;
|
|
1972
2002
|
return /^chrome-devtools-axi-bridge\.(?:js|mjs|cjs|ts)$/i.test(base);
|
|
1973
2003
|
}
|
|
1974
2004
|
return false;
|
|
1975
2005
|
}
|
|
1976
|
-
function isBridgeProcess(pid) {
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
"
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
2006
|
+
function isBridgeProcess(pid, expectedStartTime) {
|
|
2007
|
+
const identity = inspectProcessIdentity(pid);
|
|
2008
|
+
if (identity.command !== void 0) {
|
|
2009
|
+
if (!commandLineLooksLikeBridge(identity.command)) return false;
|
|
2010
|
+
} else {
|
|
2011
|
+
if (process.platform === "win32") {
|
|
2012
|
+
try {
|
|
2013
|
+
const command = execFileSync(
|
|
2014
|
+
"powershell",
|
|
2015
|
+
[
|
|
2016
|
+
"-NoProfile",
|
|
2017
|
+
"-NonInteractive",
|
|
2018
|
+
"-Command",
|
|
2019
|
+
`(Get-CimInstance Win32_Process -Filter "ProcessId=${pid}").CommandLine`
|
|
2020
|
+
],
|
|
2021
|
+
{ encoding: "utf-8", timeout: 4e3 }
|
|
2022
|
+
);
|
|
2023
|
+
if (!commandLineLooksLikeBridge(command)) return false;
|
|
2024
|
+
} catch {
|
|
2025
|
+
return false;
|
|
2026
|
+
}
|
|
2027
|
+
} else {
|
|
2028
|
+
try {
|
|
2029
|
+
const command = execFileSync("ps", ["-p", String(pid), "-o", "command="], {
|
|
2030
|
+
encoding: "utf-8",
|
|
2031
|
+
timeout: 1e3
|
|
2032
|
+
});
|
|
2033
|
+
if (!commandLineLooksLikeBridge(command)) return false;
|
|
2034
|
+
} catch {
|
|
2035
|
+
return false;
|
|
2036
|
+
}
|
|
1992
2037
|
}
|
|
1993
2038
|
}
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
encoding: "utf-8",
|
|
1997
|
-
timeout: 1e3
|
|
1998
|
-
});
|
|
1999
|
-
return commandLineLooksLikeBridge(command);
|
|
2000
|
-
} catch {
|
|
2001
|
-
return false;
|
|
2002
|
-
}
|
|
2039
|
+
if (expectedStartTime === void 0) return true;
|
|
2040
|
+
return identity.startTime !== void 0 && identity.startTime === expectedStartTime;
|
|
2003
2041
|
}
|
|
2004
2042
|
async function probeBridgeIdentity(port, sessionName) {
|
|
2005
2043
|
try {
|
|
@@ -2022,11 +2060,12 @@ async function judgeRecordedBridge(pidInfo, sessionName) {
|
|
|
2022
2060
|
if (probe.identity === "own") {
|
|
2023
2061
|
if (probe.reportedPid !== void 0) {
|
|
2024
2062
|
if (probe.reportedPid === pidInfo.pid) {
|
|
2025
|
-
const verified = isBridgeProcess(pidInfo.pid);
|
|
2063
|
+
const verified = isBridgeProcess(pidInfo.pid, pidInfo.startTime);
|
|
2026
2064
|
return {
|
|
2027
2065
|
terminate: verified,
|
|
2028
2066
|
killProcessGroup: verified,
|
|
2029
|
-
targetPid: pidInfo.pid
|
|
2067
|
+
targetPid: pidInfo.pid,
|
|
2068
|
+
expectedStartTime: pidInfo.startTime
|
|
2030
2069
|
};
|
|
2031
2070
|
}
|
|
2032
2071
|
const reportedIsBridge = isBridgeProcess(probe.reportedPid);
|
|
@@ -2036,14 +2075,14 @@ async function judgeRecordedBridge(pidInfo, sessionName) {
|
|
|
2036
2075
|
targetPid: probe.reportedPid
|
|
2037
2076
|
};
|
|
2038
2077
|
}
|
|
2039
|
-
const bridge2 = isBridgeProcess(pidInfo.pid);
|
|
2040
|
-
return { terminate: bridge2, killProcessGroup: bridge2, targetPid: pidInfo.pid };
|
|
2078
|
+
const bridge2 = isBridgeProcess(pidInfo.pid, pidInfo.startTime);
|
|
2079
|
+
return { terminate: bridge2, killProcessGroup: bridge2, targetPid: pidInfo.pid, expectedStartTime: pidInfo.startTime };
|
|
2041
2080
|
}
|
|
2042
2081
|
if (probe.identity === "other") {
|
|
2043
2082
|
return { terminate: false, killProcessGroup: false };
|
|
2044
2083
|
}
|
|
2045
|
-
const bridge = isBridgeProcess(pidInfo.pid);
|
|
2046
|
-
return { terminate: bridge, killProcessGroup: bridge, targetPid: pidInfo.pid };
|
|
2084
|
+
const bridge = isBridgeProcess(pidInfo.pid, pidInfo.startTime);
|
|
2085
|
+
return { terminate: bridge, killProcessGroup: bridge, targetPid: pidInfo.pid, expectedStartTime: pidInfo.startTime };
|
|
2047
2086
|
}
|
|
2048
2087
|
function removePidFile(pidFile) {
|
|
2049
2088
|
try {
|
|
@@ -2065,9 +2104,13 @@ function taskkillTree(pid) {
|
|
|
2065
2104
|
async function terminateBridgeProcess(pid, opts = {}) {
|
|
2066
2105
|
if (!isProcessAlive(pid)) return true;
|
|
2067
2106
|
const killProcessGroup = opts.killProcessGroup === true;
|
|
2107
|
+
const identityHolds = () => !opts.requireBridgeIdentity || isBridgeProcess(pid, opts.expectedStartTime);
|
|
2108
|
+
const refuseIfUnverified = async () => !await isProcessAlive(pid);
|
|
2068
2109
|
if (process.platform === "win32") {
|
|
2110
|
+
if (!identityHolds()) return refuseIfUnverified();
|
|
2069
2111
|
return taskkillTree(pid) && !await isProcessAlive(pid);
|
|
2070
2112
|
}
|
|
2113
|
+
if (!identityHolds()) return refuseIfUnverified();
|
|
2071
2114
|
try {
|
|
2072
2115
|
process.kill(pid, "SIGTERM");
|
|
2073
2116
|
} catch (error) {
|
|
@@ -2082,10 +2125,12 @@ async function terminateBridgeProcess(pid, opts = {}) {
|
|
|
2082
2125
|
}
|
|
2083
2126
|
return true;
|
|
2084
2127
|
}
|
|
2128
|
+
if (!identityHolds()) return refuseIfUnverified();
|
|
2085
2129
|
if (killProcessGroup) {
|
|
2086
2130
|
try {
|
|
2087
2131
|
process.kill(-pid, "SIGKILL");
|
|
2088
2132
|
} catch {
|
|
2133
|
+
if (!identityHolds()) return refuseIfUnverified();
|
|
2089
2134
|
try {
|
|
2090
2135
|
process.kill(pid, "SIGKILL");
|
|
2091
2136
|
} catch {
|
|
@@ -2188,7 +2233,9 @@ async function ensureBridge(spawnBridge = spawnBridgeProcess, notice) {
|
|
|
2188
2233
|
const verdict = await judgeRecordedBridge(pidInfo, sessionName);
|
|
2189
2234
|
if (verdict.terminate) {
|
|
2190
2235
|
await terminateBridgeProcess(verdict.targetPid ?? pidInfo.pid, {
|
|
2191
|
-
killProcessGroup: verdict.killProcessGroup
|
|
2236
|
+
killProcessGroup: verdict.killProcessGroup,
|
|
2237
|
+
requireBridgeIdentity: true,
|
|
2238
|
+
expectedStartTime: verdict.expectedStartTime
|
|
2192
2239
|
});
|
|
2193
2240
|
} else {
|
|
2194
2241
|
removePidFile(pidFile);
|
|
@@ -2466,7 +2513,9 @@ async function stopBridge() {
|
|
|
2466
2513
|
const verdict = await judgeRecordedBridge(pidInfo, resolveSessionName());
|
|
2467
2514
|
if (!verdict.terminate) return "noop";
|
|
2468
2515
|
const terminated = await terminateBridgeProcess(verdict.targetPid ?? pidInfo.pid, {
|
|
2469
|
-
killProcessGroup: verdict.killProcessGroup
|
|
2516
|
+
killProcessGroup: verdict.killProcessGroup,
|
|
2517
|
+
requireBridgeIdentity: true,
|
|
2518
|
+
expectedStartTime: verdict.expectedStartTime
|
|
2470
2519
|
});
|
|
2471
2520
|
clearSelectedPageId();
|
|
2472
2521
|
return terminated ? "stopped" : "failed";
|
|
@@ -166,9 +166,9 @@ This section is one continuous sequence — don't stop partway through. Do NOT u
|
|
|
166
166
|
|
|
167
167
|
Put results in `<skill-name>-workspace/` as a sibling to the skill directory. Within the workspace, organize results by iteration (`iteration-1/`, `iteration-2/`, etc.) and within that, each test case gets a directory (`eval-0/`, `eval-1/`, etc.). Don't create all of this upfront — just create directories as you go.
|
|
168
168
|
|
|
169
|
-
### Step 1:
|
|
169
|
+
### Step 1: Schedule paired runs (with-skill AND baseline)
|
|
170
170
|
|
|
171
|
-
For each test case,
|
|
171
|
+
For each test case, prepare paired runs — one with the skill, one baseline. Read-only runs may be batched; Pie uses bounded concurrency (default 4), not unlimited simultaneous execution. Default `mode: "read"` tasks cannot write source files: ask them to return outputs and grading evidence, then have the parent persist artifacts, metadata, timing and grades. When evaluation genuinely requires file edits, use explicit `mode: "edit"` with exactly one task per call, wait for it to finish before any parent edit or next edit task, and review its changes. The workspace is shared, not isolated. Use parent-owned persistence or serialized single edit tasks for all evaluation writes; a save-path instruction does not grant a read task write permission.
|
|
172
172
|
|
|
173
173
|
**With-skill run:**
|
|
174
174
|
|
|
@@ -177,7 +177,7 @@ Execute this task:
|
|
|
177
177
|
- Skill path: <path-to-skill>
|
|
178
178
|
- Task: <eval prompt>
|
|
179
179
|
- Input files: <eval files if any, or "none">
|
|
180
|
-
-
|
|
180
|
+
- Return outputs for parent persistence to: <workspace>/iteration-<N>/eval-<ID>/with_skill/outputs/ (or use a serialized single edit task)
|
|
181
181
|
- Outputs to save: <what the user cares about — e.g., "the .docx file", "the final CSV">
|
|
182
182
|
```
|
|
183
183
|
|
|
@@ -206,29 +206,28 @@ Update the `eval_metadata.json` files and `evals/evals.json` with the assertions
|
|
|
206
206
|
|
|
207
207
|
### Step 3: As runs complete, capture timing data
|
|
208
208
|
|
|
209
|
-
|
|
209
|
+
Pie exposes per-task timing as `task.details.durationMs` when available and aggregate wall time as result `details.totalDuration` (milliseconds). It does not supply `total_tokens` or `duration_ms` notification fields. Have the parent persist available per-run timing to `timing.json`, converting units for the viewer:
|
|
210
210
|
|
|
211
211
|
```json
|
|
212
212
|
{
|
|
213
|
-
"total_tokens": 84852,
|
|
214
213
|
"duration_ms": 23332,
|
|
215
214
|
"total_duration_seconds": 23.3
|
|
216
215
|
}
|
|
217
216
|
```
|
|
218
217
|
|
|
219
|
-
|
|
218
|
+
Here `duration_ms` is an artifact field derived from `task.details.durationMs`, not a native notification field. Keep aggregate `totalDuration` separate from per-run duration; concurrency means it is not the sum of task times. If timing is absent, mark it unavailable rather than inventing a value. Do not report token counts unless separate instrumentation actually provides them; omit `total_tokens` otherwise. Viewer/aggregator default zeros are not measured token usage.
|
|
220
219
|
|
|
221
220
|
### Step 4: Grade, aggregate, and launch the viewer
|
|
222
221
|
|
|
223
222
|
Once all runs are done:
|
|
224
223
|
|
|
225
|
-
1. **Grade each run** — spawn a grader subagent (or grade inline) that reads `agents/grader.md` and evaluates each assertion against the outputs.
|
|
224
|
+
1. **Grade each run** — spawn a grader subagent (or grade inline) that reads `agents/grader.md` and evaluates each assertion against the outputs. Have the parent save returned grades to `grading.json` in each run directory (or use a serialized single edit task); read graders must not write files. The grading.json expectations array must use the fields `text`, `passed`, and `evidence` (not `name`/`met`/`details` or other variants) — the viewer depends on these exact field names. For assertions that can be checked programmatically, write and run a script rather than eyeballing it — scripts are faster, more reliable, and can be reused across iterations.
|
|
226
225
|
|
|
227
226
|
2. **Aggregate into benchmark** — run the aggregation script from the skill-creator directory:
|
|
228
227
|
```bash
|
|
229
228
|
node <skill-creator-path>/scripts/aggregate_benchmark.mjs <workspace>/iteration-N --skill-name <name>
|
|
230
229
|
```
|
|
231
|
-
This produces `benchmark.json` and `benchmark.md` with pass_rate
|
|
230
|
+
This produces `benchmark.json` and `benchmark.md` with pass_rate and available timing for each configuration, with mean ± stddev and the delta. Token fields are meaningful only with separate instrumentation; label them unavailable otherwise. If generating benchmark.json manually, see `references/schemas.md` for the exact schema the viewer expects.
|
|
232
231
|
Put each with_skill version before its baseline counterpart.
|
|
233
232
|
|
|
234
233
|
3. **Do an analyst pass** — read the benchmark data and surface patterns the aggregate stats might hide. See `agents/analyzer.md` (the "Analyzing Benchmark Results" section) for what to look for — things like assertions that always pass regardless of skill (non-discriminating), high-variance evals (possibly flaky), and time/token tradeoffs.
|