@pome-sh/cli 0.23.4 → 0.23.5
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/README.md
CHANGED
|
@@ -99,6 +99,16 @@ Three rules CI must honor:
|
|
|
99
99
|
excluded from the verdict fraction (`3 of 4 passed · 1 incomplete`) so neither
|
|
100
100
|
is counted as a pass nor charged to the agent as a loss — but a group holding
|
|
101
101
|
one cannot exit `0`.
|
|
102
|
+
- **`pome fix-prompt` uses the same codes, and its `1` is only ever
|
|
103
|
+
INCOMPLETE.** Building a prompt for a failed run set exits `0` (the prompt is
|
|
104
|
+
on stdout, and stdout being non-empty is the signal that there was something
|
|
105
|
+
to fix); an all-green root exits `0` with nothing on stdout; a bad argument or
|
|
106
|
+
a root with no readable run sets exits `5`. `1` is reserved for the one case
|
|
107
|
+
where the newest non-passing set was never fully graded: no prompt is built,
|
|
108
|
+
because a run whose checks never ran is not evidence of an agent defect. This
|
|
109
|
+
matches `pome run`, where `1` also covers INCOMPLETE — the two commands do not
|
|
110
|
+
disagree about what an ungraded run exits, and `verdict.json`'s `state` stays
|
|
111
|
+
the field to read when a script needs the reason rather than the code.
|
|
102
112
|
|
|
103
113
|
## Development
|
|
104
114
|
|
package/dist/build-info.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"package": "pome-sh",
|
|
3
|
-
"version": "0.23.
|
|
4
|
-
"git_sha": "
|
|
5
|
-
"build_time": "2026-08-
|
|
3
|
+
"version": "0.23.5",
|
|
4
|
+
"git_sha": "4f55e6deab92cf0ff34dd769c73763fc9b480375",
|
|
5
|
+
"build_time": "2026-08-10T15:36:42.602Z"
|
|
6
6
|
}
|
|
@@ -117,13 +117,15 @@ function groupRunSets(trials) {
|
|
|
117
117
|
(a, b) => a.verdict.finalized_at.localeCompare(b.verdict.finalized_at)
|
|
118
118
|
);
|
|
119
119
|
const last = bucket[bucket.length - 1];
|
|
120
|
+
const hasFailed = bucket.some((t) => t.verdict.state === "fail");
|
|
121
|
+
const allPassed = bucket.every((t) => t.verdict.state === "pass");
|
|
120
122
|
sets.push({
|
|
121
123
|
groupId: bucket[0].verdict.group_id,
|
|
122
124
|
taskName: bucket[0].verdict.task_name,
|
|
123
125
|
taskPath: bucket[0].verdict.task_path,
|
|
124
126
|
trials: bucket,
|
|
125
127
|
latestFinalizedAt: last.verdict.finalized_at,
|
|
126
|
-
|
|
128
|
+
outcome: hasFailed ? "fail" : allPassed ? "pass" : "incomplete"
|
|
127
129
|
});
|
|
128
130
|
}
|
|
129
131
|
sets.sort((a, b) => a.latestFinalizedAt.localeCompare(b.latestFinalizedAt));
|
|
@@ -131,14 +133,26 @@ function groupRunSets(trials) {
|
|
|
131
133
|
}
|
|
132
134
|
function latestFailedRunSet(sets) {
|
|
133
135
|
for (let i = sets.length - 1; i >= 0; i -= 1) {
|
|
134
|
-
if (sets[i].
|
|
136
|
+
if (sets[i].outcome === "fail") return sets[i];
|
|
137
|
+
}
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
function latestIncompleteRunSet(sets) {
|
|
141
|
+
for (let i = sets.length - 1; i >= 0; i -= 1) {
|
|
142
|
+
if (sets[i].outcome === "incomplete") return sets[i];
|
|
135
143
|
}
|
|
136
144
|
return null;
|
|
137
145
|
}
|
|
138
146
|
async function discoverRunSet(target) {
|
|
139
147
|
const anchorResult = await readVerdictArtifactDetailed(target);
|
|
140
148
|
if (anchorResult.status === "stale-version") {
|
|
141
|
-
return {
|
|
149
|
+
return {
|
|
150
|
+
kind: "trial-dir",
|
|
151
|
+
set: null,
|
|
152
|
+
incompleteSet: null,
|
|
153
|
+
totalSets: 0,
|
|
154
|
+
staleVersionCount: 1
|
|
155
|
+
};
|
|
142
156
|
}
|
|
143
157
|
if (anchorResult.status === "ok") {
|
|
144
158
|
const anchor = anchorResult.trial;
|
|
@@ -151,18 +165,27 @@ async function discoverRunSet(target) {
|
|
|
151
165
|
return {
|
|
152
166
|
kind: "trial-dir",
|
|
153
167
|
set: own,
|
|
168
|
+
incompleteSet: null,
|
|
154
169
|
totalSets: Math.max(sets2.length, 1),
|
|
155
170
|
staleVersionCount: staleVersionDirs2.length
|
|
156
171
|
};
|
|
157
172
|
}
|
|
158
173
|
if (!existsSync(target)) {
|
|
159
|
-
return {
|
|
174
|
+
return {
|
|
175
|
+
kind: "root",
|
|
176
|
+
set: null,
|
|
177
|
+
incompleteSet: null,
|
|
178
|
+
totalSets: 0,
|
|
179
|
+
staleVersionCount: 0
|
|
180
|
+
};
|
|
160
181
|
}
|
|
161
182
|
const { trials, staleVersionDirs } = await scanVerdictArtifactsDetailed(target);
|
|
162
183
|
const sets = groupRunSets(trials);
|
|
184
|
+
const failedSet = latestFailedRunSet(sets);
|
|
163
185
|
return {
|
|
164
186
|
kind: "root",
|
|
165
|
-
set:
|
|
187
|
+
set: failedSet,
|
|
188
|
+
incompleteSet: failedSet ? null : latestIncompleteRunSet(sets),
|
|
166
189
|
totalSets: sets.length,
|
|
167
190
|
staleVersionCount: staleVersionDirs.length
|
|
168
191
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { newGroupId, criterionPhrase } from './chunk-RGZBC7NF.js';
|
|
2
|
-
import { runTaskHosted, resolveRunAgentIdentity } from './chunk-
|
|
2
|
+
import { runTaskHosted, resolveRunAgentIdentity } from './chunk-RSQY6UIL.js';
|
|
3
3
|
import './chunk-XOWIA7NR.js';
|
|
4
4
|
import { createHostedClient, parseTaskFile, outcomeOf } from './chunk-GFTFMA3T.js';
|
|
5
5
|
import './chunk-NW7HGA2K.js';
|
package/dist/src/cli/main.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { DEFAULT_CONTROL_PLANE_URL, DEFAULT_DASHBOARD_URL, clearLocalCredentials, friendlyHostedError, runSessionCreate, runSessionList, runSessionStop, resolveCredentials, runTaskHosted, discoverRunSet, VERDICT_ARTIFACT_VERSION, loadTrialEvents, persistCredentialsAfterLogin, DEFAULT_DOCS_SITE_ORIGIN, resolveSeams, resolveCachedAgentId, readLinkCache, postAgentResolver, writeLinkCache, ensurePomeGitignored } from '../../chunk-
|
|
2
|
+
import { DEFAULT_CONTROL_PLANE_URL, DEFAULT_DASHBOARD_URL, clearLocalCredentials, friendlyHostedError, runSessionCreate, runSessionList, runSessionStop, resolveCredentials, runTaskHosted, discoverRunSet, VERDICT_ARTIFACT_VERSION, loadTrialEvents, persistCredentialsAfterLogin, DEFAULT_DOCS_SITE_ORIGIN, resolveSeams, resolveCachedAgentId, readLinkCache, postAgentResolver, writeLinkCache, ensurePomeGitignored } from '../../chunk-RSQY6UIL.js';
|
|
3
3
|
import { readManifest, writeManifest, MANIFEST_JSON, readRequiredManifest, normalizeManifestTwins } from '../../chunk-XOWIA7NR.js';
|
|
4
4
|
import { assetPath, runTask, resolvePackageRoot, DEMO_TASK_NAME, demoTaskPath } from '../../chunk-YUKMLGYF.js';
|
|
5
5
|
import '../../chunk-XDU6TD4O.js';
|
|
6
6
|
import '../../chunk-CBFKZZBR.js';
|
|
7
|
-
import { parseTaskFile, scoreStatus, runScoreLine, readLatestRun, readMetaSummary, readConfigTwins, scoreCountsSummary, markerFor,
|
|
7
|
+
import { parseTaskFile, scoreStatus, runScoreLine, readLatestRun, readMetaSummary, outcomeOf, readConfigTwins, scoreCountsSummary, markerFor, criterionMarkerLabel, twinSkipSuffix, readCodeCriteria, createHostedClient, toTwinHttpEvent, redactJsonl, scoreFromFinalizeResponse, parseGitHubSeedState, uploadRunBlobs, isPreSatisfied } from '../../chunk-GFTFMA3T.js';
|
|
8
8
|
import '../../chunk-NW7HGA2K.js';
|
|
9
9
|
import { MOUNTED_TWINS, deriveAgentSlug, exitCodeFor, HostedUsageError, HostedOrchError, HostedAuthError, HostedQuotaError } from '../../chunk-7AMIVWUB.js';
|
|
10
10
|
import { TAPE_ASSERTABLE_TOOLS } from '../../chunk-FKZZWWYC.js';
|
|
@@ -4348,6 +4348,14 @@ function criterionMarker(c) {
|
|
|
4348
4348
|
function failedResults(verdict) {
|
|
4349
4349
|
return verdict.criteria_results.filter((r) => outcomeOf(r) === "failed");
|
|
4350
4350
|
}
|
|
4351
|
+
function isGraded(t) {
|
|
4352
|
+
return t.verdict.state !== "incomplete";
|
|
4353
|
+
}
|
|
4354
|
+
function ungradedCount(verdict) {
|
|
4355
|
+
return verdict.criteria_results.filter(
|
|
4356
|
+
(r) => !isPreSatisfied(r) && outcomeOf(r) !== "passed" && outcomeOf(r) !== "failed"
|
|
4357
|
+
).length;
|
|
4358
|
+
}
|
|
4351
4359
|
function flattenLine(text, max = 300) {
|
|
4352
4360
|
const flat = text.replace(/\s+/g, " ").trim();
|
|
4353
4361
|
return flat.length > max ? `${flat.slice(0, max - 1)}\u2026` : flat;
|
|
@@ -4355,10 +4363,14 @@ function flattenLine(text, max = 300) {
|
|
|
4355
4363
|
function renderGroupedSignatures(trials) {
|
|
4356
4364
|
const byCriterion = /* @__PURE__ */ new Map();
|
|
4357
4365
|
const outcomesSeen = /* @__PURE__ */ new Map();
|
|
4366
|
+
const gradedFor = /* @__PURE__ */ new Map();
|
|
4358
4367
|
for (const trial of trials) {
|
|
4359
4368
|
for (const result of trial.verdict.criteria_results) {
|
|
4360
4369
|
const key = result.criterion.text;
|
|
4361
4370
|
const outcome = isPreSatisfied(result) ? "excluded" : outcomeOf(result);
|
|
4371
|
+
if (outcome === "passed" || outcome === "failed") {
|
|
4372
|
+
gradedFor.set(key, (gradedFor.get(key) ?? 0) + 1);
|
|
4373
|
+
}
|
|
4362
4374
|
if (outcome === "failed") {
|
|
4363
4375
|
const entry = byCriterion.get(key) ?? {
|
|
4364
4376
|
marker: criterionMarker(result.criterion),
|
|
@@ -4381,12 +4393,12 @@ function renderGroupedSignatures(trials) {
|
|
|
4381
4393
|
else if (seen.size === 1 && seen.has("excluded")) preSatisfiedEverywhere.push(key);
|
|
4382
4394
|
else notUniformlyEvaluated.push(key);
|
|
4383
4395
|
}
|
|
4384
|
-
const completed = trials.length;
|
|
4385
4396
|
const blocks = [...byCriterion.entries()].sort((a, b) => b[1].hits.length - a[1].hits.length).map(([text, { marker, hits }], idx) => {
|
|
4386
4397
|
const lines = hits.map(
|
|
4387
4398
|
(h) => ` - ${h.label}: ${flattenLine(h.reason)}`
|
|
4388
4399
|
);
|
|
4389
|
-
|
|
4400
|
+
const graded = gradedFor.get(text) ?? hits.length;
|
|
4401
|
+
return `${idx + 1}. ${marker} ${flattenLine(text)} \u2014 failed in ${hits.length} of ${graded} trials that graded it
|
|
4390
4402
|
${lines.join("\n")}`;
|
|
4391
4403
|
});
|
|
4392
4404
|
if (blocks.length === 0 && passedEverywhere.length === 0 && preSatisfiedEverywhere.length === 0 && notUniformlyEvaluated.length === 0) {
|
|
@@ -4414,18 +4426,19 @@ ${lines.join("\n")}`;
|
|
|
4414
4426
|
return [...blocks, ...notes].join("\n");
|
|
4415
4427
|
}
|
|
4416
4428
|
function representativeFailingTrial(trials) {
|
|
4417
|
-
const failing = trials.filter((t) =>
|
|
4429
|
+
const failing = trials.filter((t) => t.verdict.state === "fail");
|
|
4418
4430
|
if (failing.length === 0) return null;
|
|
4419
4431
|
return failing.reduce(
|
|
4420
4432
|
(worst, t) => failedResults(t.verdict).length > failedResults(worst.verdict).length ? t : worst
|
|
4421
4433
|
);
|
|
4422
4434
|
}
|
|
4423
4435
|
function buildGroupFixUserPrompt(ctx) {
|
|
4424
|
-
const
|
|
4425
|
-
const
|
|
4436
|
+
const incomplete = ctx.trials.filter((t) => !isGraded(t));
|
|
4437
|
+
const completed = ctx.trials.length - incomplete.length;
|
|
4438
|
+
const passed = ctx.trials.filter((t) => t.verdict.state === "pass").length;
|
|
4426
4439
|
const representative = representativeFailingTrial(ctx.trials);
|
|
4427
4440
|
const otherFailing = ctx.trials.filter(
|
|
4428
|
-
(t) =>
|
|
4441
|
+
(t) => t.verdict.state === "fail" && t !== representative
|
|
4429
4442
|
);
|
|
4430
4443
|
const signatures = redactSecrets(
|
|
4431
4444
|
renderGroupedSignatures(ctx.trials)
|
|
@@ -4439,9 +4452,11 @@ function buildGroupFixUserPrompt(ctx) {
|
|
|
4439
4452
|
)
|
|
4440
4453
|
);
|
|
4441
4454
|
const promptBlock = ctx.task ? redactSecrets(ctx.task.prompt) : `(task file not found at ${ctx.trials[0]?.verdict.task_path ?? "?"} \u2014 criteria above come from the cloud verdicts)`;
|
|
4455
|
+
const tally = completed === 0 ? "no trial in this set was graded end to end" : `${passed} of ${completed} completed trials passed`;
|
|
4456
|
+
const gapNote = incomplete.length > 0 ? ` \xB7 ${incomplete.length} INCOMPLETE (counted in nothing below \u2014 see the last section)` : "";
|
|
4442
4457
|
const sections = [];
|
|
4443
4458
|
sections.push(`## Run set (cloud-judged)
|
|
4444
|
-
task ${redactSecrets(ctx.taskName)} \xB7 ${ctx.groupId ? `group ${ctx.groupId}` : "single run"} \xB7 ${
|
|
4459
|
+
task ${redactSecrets(ctx.taskName)} \xB7 ${ctx.groupId ? `group ${ctx.groupId}` : "single run"} \xB7 ${tally}${gapNote}`);
|
|
4445
4460
|
sections.push(`## Grouped failure signatures (from the cloud judge)
|
|
4446
4461
|
${escapeTagContent(signatures)}`);
|
|
4447
4462
|
sections.push(`## Task prompt (what the agent was told to do)
|
|
@@ -4463,6 +4478,17 @@ ${escapeTagContent(trace)}
|
|
|
4463
4478
|
return `- ${t.label} \u2014 failed: ${failed || "(see verdict)"} \u2014 trace at ${join(t.runDir, "events.jsonl")}`;
|
|
4464
4479
|
});
|
|
4465
4480
|
sections.push(`## Other failing trials (traces on disk)
|
|
4481
|
+
${escapeTagContent(redactSecrets(lines.join("\n")))}`);
|
|
4482
|
+
}
|
|
4483
|
+
if (incomplete.length > 0) {
|
|
4484
|
+
const lines = incomplete.map(
|
|
4485
|
+
(t) => `- ${t.label} \u2014 ${ungradedCount(t.verdict)} criterion(s) never graded \u2014 trace at ${join(t.runDir, "events.jsonl")}`
|
|
4486
|
+
);
|
|
4487
|
+
sections.push(`## Trials the grader never finished (INCOMPLETE)
|
|
4488
|
+
The grader never reached every criterion in these trials, so they are neither
|
|
4489
|
+
passes nor failures and are counted in no fraction above. Do NOT treat them as
|
|
4490
|
+
evidence for or against any fix: a criterion that never ran is a grader or seed
|
|
4491
|
+
gap, not something the agent did wrong.
|
|
4466
4492
|
${escapeTagContent(redactSecrets(lines.join("\n")))}`);
|
|
4467
4493
|
}
|
|
4468
4494
|
if (passed > 0 && passed < completed) {
|
|
@@ -4495,7 +4521,7 @@ var DEFAULT_AGENT_FILE = "examples/agents/scripted-triage-agent.ts";
|
|
|
4495
4521
|
var DEFAULT_AGENT_COMMAND = `node ${DEFAULT_AGENT_FILE}`;
|
|
4496
4522
|
var MANIFEST_SCHEMA_URL = "https://pome.sh/schemas/v1/pome.json";
|
|
4497
4523
|
function readPackageVersion() {
|
|
4498
|
-
if ("0.23.
|
|
4524
|
+
if ("0.23.5".length > 0) return "0.23.5";
|
|
4499
4525
|
try {
|
|
4500
4526
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
4501
4527
|
const candidates = [
|
|
@@ -4988,7 +5014,7 @@ function createProgram() {
|
|
|
4988
5014
|
taskForRuns.config.runs
|
|
4989
5015
|
);
|
|
4990
5016
|
if (k > 1) {
|
|
4991
|
-
const { runTrialGroup } = await import('../../runTrialGroup-
|
|
5017
|
+
const { runTrialGroup } = await import('../../runTrialGroup-NIBA5KRF.js');
|
|
4992
5018
|
const fileForRerun = relative(process.cwd(), file);
|
|
4993
5019
|
const rerunCommand = defaultTask ? options.trials !== void 0 ? `pome run -n ${k}` : "pome run" : `pome run ${fileForRerun && !fileForRerun.startsWith("..") ? fileForRerun : file} -n ${k}`;
|
|
4994
5020
|
const groupResult = await runTrialGroup({
|
|
@@ -5202,6 +5228,31 @@ function createProgram() {
|
|
|
5202
5228
|
return;
|
|
5203
5229
|
}
|
|
5204
5230
|
if (!discovery.set) {
|
|
5231
|
+
const incomplete = discovery.incompleteSet;
|
|
5232
|
+
if (incomplete) {
|
|
5233
|
+
const ungradedTrials = incomplete.trials.filter(
|
|
5234
|
+
(t) => t.verdict.state === "incomplete"
|
|
5235
|
+
).length;
|
|
5236
|
+
const gradedFailures = incomplete.trials.reduce(
|
|
5237
|
+
(n, t) => n + t.verdict.criteria_results.filter((r) => outcomeOf(r) === "failed").length,
|
|
5238
|
+
0
|
|
5239
|
+
);
|
|
5240
|
+
const which = `task ${incomplete.taskName}${incomplete.groupId ? ` \xB7 group ${incomplete.groupId}` : ""}`;
|
|
5241
|
+
console.error(
|
|
5242
|
+
`Not routed to fix-prompt: no run set under ${root} failed outright. The most recent non-passing one (${which}) is INCOMPLETE \u2014 ${ungradedTrials} of ${incomplete.trials.length} trial(s) have criteria the grader never graded.`
|
|
5243
|
+
);
|
|
5244
|
+
if (gradedFailures > 0) {
|
|
5245
|
+
console.error(
|
|
5246
|
+
`${gradedFailures} criterion result(s) in that set WERE graded and did fail, so this is not only a grading gap \u2014 but no trial in it was graded end to end, and a fix prompt built from a partial grading would claim more than was checked. Re-run \`pome run ${incomplete.taskPath}\` to grade the rest, or point fix-prompt straight at one trial (\`pome fix-prompt ${incomplete.trials[0].runDir}\`) to build one from the partial grading anyway.`
|
|
5247
|
+
);
|
|
5248
|
+
} else {
|
|
5249
|
+
console.error(
|
|
5250
|
+
`Nothing in that set was graded and failed, so it is a grader/seed gap, not an agent defect, and fix-prompt will not hand it to your coding agent. Re-run \`pome run ${incomplete.taskPath}\` to grade those criteria; if they come back ungraded, the gap is in the task's checks or its seed, not in your prompt.`
|
|
5251
|
+
);
|
|
5252
|
+
}
|
|
5253
|
+
process.exitCode = 1;
|
|
5254
|
+
return;
|
|
5255
|
+
}
|
|
5205
5256
|
console.error(
|
|
5206
5257
|
`Nothing to fix: the latest run sets under ${root} all passed.`
|
|
5207
5258
|
);
|
package/package.json
CHANGED