@pome-sh/cli 0.23.32 → 0.23.34

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "package": "pome-sh",
3
- "version": "0.23.32",
4
- "git_sha": "07c526747a7654a4aea3b1d8f417da3c9d653238",
5
- "build_time": "2026-08-13T01:00:51.116Z"
3
+ "version": "0.23.34",
4
+ "git_sha": "0c6c21c02b475a025c5b83bc77f158832cd0dfe2",
5
+ "build_time": "2026-08-13T01:18:05.857Z"
6
6
  }
@@ -2,14 +2,13 @@ import { readManifest, normalizeManifestTwins } from './chunk-ABM3CMQB.js';
2
2
  import { createHostedClient, perTwinReturnedByCloud, parseTaskFile, runAgentCommand, writeRunArtifactsCore, toTwinHttpEvent, redactJsonl, uploadRunBlobs, scoreFromFinalizeResponse, scoreStatus, evaluationCounts } from './chunk-ZTINFLSV.js';
3
3
  import { MOUNTED_TWINS, HostedAuthError, HostedDiscardRefusedError, HostedQuotaError, HostedOrchError, HostedTrialError, agentResponseSchema } from './chunk-X66JOOO7.js';
4
4
  import { redactSecrets, redactEvent } from './chunk-SG6ZTIMT.js';
5
- import { existsSync } from 'node:fs';
6
- import { rm, readFile, stat, mkdir, writeFile, chmod, mkdtemp, readdir } from 'node:fs/promises';
5
+ import { randomUUID, createHash } from 'node:crypto';
6
+ import { rm, readFile, stat, mkdir, writeFile, chmod, mkdtemp, readdir, rename } from 'node:fs/promises';
7
7
  import { join, dirname } from 'node:path';
8
8
  import { tmpdir, homedir } from 'node:os';
9
9
  import { execFile } from 'node:child_process';
10
10
  import { promisify } from 'node:util';
11
11
  import { createInterface } from 'node:readline';
12
- import { randomUUID, createHash } from 'node:crypto';
13
12
 
14
13
  // src/hosted/runSets.ts
15
14
  function groupRunSets(trials) {
@@ -62,12 +61,16 @@ var VALID_STATES = /* @__PURE__ */ new Set([
62
61
  "incomplete"
63
62
  ]);
64
63
  async function writeVerdictArtifact(runDir, verdict) {
65
- await writeFile(
66
- join(runDir, VERDICT_FILENAME),
67
- `${JSON.stringify(verdict, null, 2)}
68
- `,
69
- "utf8"
70
- );
64
+ const tmpPath = join(runDir, `.${VERDICT_FILENAME}.${process.pid}.${randomUUID()}.tmp`);
65
+ try {
66
+ await writeFile(tmpPath, `${JSON.stringify(verdict, null, 2)}
67
+ `, "utf8");
68
+ await rename(tmpPath, join(runDir, VERDICT_FILENAME));
69
+ } catch (err) {
70
+ await rm(tmpPath, { force: true }).catch(() => {
71
+ });
72
+ throw err;
73
+ }
71
74
  }
72
75
  function looksLikeVerdictArtifactBase(parsed) {
73
76
  if (typeof parsed !== "object" || parsed === null) return false;
@@ -100,13 +103,23 @@ function isVerdictArtifact(parsed) {
100
103
  if (typeof v.total !== "number") return false;
101
104
  return true;
102
105
  }
106
+ var MISSING_ERROR_CODES = /* @__PURE__ */ new Set([
107
+ "ENOENT",
108
+ "ENOTDIR",
109
+ "ELOOP",
110
+ "ENAMETOOLONG"
111
+ ]);
112
+ function isMissingFileError(err) {
113
+ const code = err?.code;
114
+ return typeof code === "string" && MISSING_ERROR_CODES.has(code);
115
+ }
103
116
  async function readVerdictArtifactDetailed(runDir) {
104
117
  const path = join(runDir, VERDICT_FILENAME);
105
118
  let raw;
106
119
  try {
107
120
  raw = await readFile(path, "utf8");
108
- } catch {
109
- return { status: "unreadable" };
121
+ } catch (err) {
122
+ return isMissingFileError(err) ? { status: "missing" } : { status: "unreadable" };
110
123
  }
111
124
  let parsed;
112
125
  try {
@@ -143,9 +156,7 @@ async function scanVerdictArtifactsDetailed(artifactsRoot) {
143
156
  const result = await readVerdictArtifactDetailed(runDir);
144
157
  if (result.status === "ok") trials.push(result.trial);
145
158
  else if (result.status === "stale-version") staleVersionDirs.push(runDir);
146
- else if (result.status === "unreadable" && existsSync(join(runDir, VERDICT_FILENAME))) {
147
- unreadableDirs.push(runDir);
148
- }
159
+ else if (result.status === "unreadable") unreadableDirs.push(runDir);
149
160
  }
150
161
  }
151
162
  unreadableDirs.sort();
@@ -164,7 +175,7 @@ async function discoverRunSet(target) {
164
175
  unreadablePaths: []
165
176
  };
166
177
  }
167
- if (anchorResult.status === "unreadable" && existsSync(join(target, VERDICT_FILENAME))) {
178
+ if (anchorResult.status === "unreadable") {
168
179
  return {
169
180
  kind: "trial-dir",
170
181
  set: null,
@@ -193,17 +204,6 @@ async function discoverRunSet(target) {
193
204
  unreadablePaths: unreadableDirs2
194
205
  };
195
206
  }
196
- if (!existsSync(target)) {
197
- return {
198
- kind: "root",
199
- set: null,
200
- incompleteSet: null,
201
- totalSets: 0,
202
- staleVersionCount: 0,
203
- unreadableCount: 0,
204
- unreadablePaths: []
205
- };
206
- }
207
207
  const { trials, staleVersionDirs, unreadableDirs } = await scanVerdictArtifactsDetailed(target);
208
208
  const sets = groupRunSets(trials);
209
209
  const failedSet = latestFailedRunSet(sets);
@@ -1,5 +1,5 @@
1
1
  import { newGroupId, criterionPhrase } from './chunk-RGZBC7NF.js';
2
- import { runTaskHosted, resolveRunAgentIdentity } from './chunk-A2LGBYJG.js';
2
+ import { runTaskHosted, resolveRunAgentIdentity } from './chunk-ARAYJGDT.js';
3
3
  import './chunk-ABM3CMQB.js';
4
4
  import { createHostedClient, parseTaskFile, outcomeOf } from './chunk-ZTINFLSV.js';
5
5
  import './chunk-NW7HGA2K.js';
@@ -1,5 +1,5 @@
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, persistCredentialsAfterLogin, DEFAULT_DOCS_SITE_ORIGIN, resolveSeams, resolveCachedAgentId, readLinkCache, postAgentResolver, writeLinkCache, ensurePomeGitignored } from '../../chunk-A2LGBYJG.js';
2
+ import { DEFAULT_CONTROL_PLANE_URL, DEFAULT_DASHBOARD_URL, clearLocalCredentials, friendlyHostedError, runSessionCreate, runSessionList, runSessionStop, resolveCredentials, runTaskHosted, discoverRunSet, VERDICT_ARTIFACT_VERSION, persistCredentialsAfterLogin, DEFAULT_DOCS_SITE_ORIGIN, resolveSeams, resolveCachedAgentId, readLinkCache, postAgentResolver, writeLinkCache, ensurePomeGitignored } from '../../chunk-ARAYJGDT.js';
3
3
  import { readManifest, writeManifest, MANIFEST_JSON, readRequiredManifest, normalizeManifestTwins } from '../../chunk-ABM3CMQB.js';
4
4
  import { assetPath, runTask, resolvePackageRoot, DEMO_TASK_NAME, demoTaskPath } from '../../chunk-GEC6MJV5.js';
5
5
  import '../../chunk-XDU6TD4O.js';
@@ -3064,7 +3064,22 @@ async function runChecksCommand(twinArg, opts) {
3064
3064
  // src/task/insertCriterion.ts
3065
3065
  var HEADING_RE = /^##\s+Success Criteria\s*$/;
3066
3066
  var NEXT_HEADING_RE = /^##\s+/;
3067
- var CRITERION_RE = /^[-*]\s+\[(?:code|model)(?::[a-z][a-z0-9_-]*)?(?:\s+always-scored)?\]\s+.+$/;
3067
+ var CRITERION_RE = /^[-*]\s+\[(code|model)(?::([a-z][a-z0-9_-]*))?(\s+always-scored)?\]\s+(.+)$/;
3068
+ function identityKey(criterion) {
3069
+ return `${criterion.kind}\0${criterion.twin ?? ""}\0${criterion.text}`;
3070
+ }
3071
+ function readCriterionLine(line) {
3072
+ const match = line.trim().match(CRITERION_RE);
3073
+ if (!match) return void 0;
3074
+ return { kind: match[1], tag: match[2], text: match[4].trim() };
3075
+ }
3076
+ function primaryTwin(source) {
3077
+ try {
3078
+ return readConfigTwins(source)[0];
3079
+ } catch {
3080
+ return void 0;
3081
+ }
3082
+ }
3068
3083
  var MissingCriteriaSectionError = class extends Error {
3069
3084
  constructor(path) {
3070
3085
  super(
@@ -3074,11 +3089,15 @@ var MissingCriteriaSectionError = class extends Error {
3074
3089
  }
3075
3090
  };
3076
3091
  var DuplicateCriterionError = class extends Error {
3077
- constructor(path, line) {
3092
+ constructor(path, line, existing = line) {
3093
+ const differs = existing.trim() !== line.trim();
3078
3094
  super(
3079
3095
  `${path} already has this criterion:
3080
- ${line}
3081
- Adding it again would score it twice and inflate the task's denominator.`
3096
+ ${existing.trim()}
3097
+ ` + (differs ? `which is the same check as the one being added:
3098
+ ${line.trim()}
3099
+ \u2014 a marker annotation or a twin tag does not make it a second check.
3100
+ ` : "") + `Adding it again would score it twice and inflate the task's denominator.`
3082
3101
  );
3083
3102
  this.name = "DuplicateCriterionError";
3084
3103
  }
@@ -3094,13 +3113,33 @@ function insertCriterion(source, line, path = "this task file") {
3094
3113
  break;
3095
3114
  }
3096
3115
  }
3116
+ const primary = primaryTwin(source);
3117
+ const declared = /* @__PURE__ */ new Map();
3118
+ for (const criterion of readCodeCriteria(source)) {
3119
+ declared.set(
3120
+ identityKey({ kind: "code", twin: criterion.twin, text: criterion.text }),
3121
+ `- ${criterion.marker} ${criterion.text}`
3122
+ );
3123
+ }
3097
3124
  let insertAt = -1;
3098
3125
  for (let i = start + 1; i < end; i += 1) {
3099
- const existing = lines[i].trim();
3100
- if (!CRITERION_RE.test(existing)) continue;
3101
- if (existing === line.trim()) throw new DuplicateCriterionError(path, line);
3126
+ const parsed = readCriterionLine(lines[i]);
3127
+ if (!parsed) continue;
3128
+ if (parsed.kind === "model") {
3129
+ declared.set(
3130
+ identityKey({ kind: "model", twin: parsed.tag ?? primary, text: parsed.text }),
3131
+ lines[i].trim()
3132
+ );
3133
+ }
3102
3134
  insertAt = i + 1;
3103
3135
  }
3136
+ const incoming = readCriterionLine(line);
3137
+ if (incoming) {
3138
+ const stored = declared.get(
3139
+ identityKey({ kind: incoming.kind, twin: incoming.tag ?? primary, text: incoming.text })
3140
+ );
3141
+ if (stored !== void 0) throw new DuplicateCriterionError(path, line, stored);
3142
+ }
3104
3143
  if (insertAt === -1) {
3105
3144
  insertAt = lines[start + 1]?.trim() === "" ? start + 2 : start + 1;
3106
3145
  }
@@ -4541,7 +4580,7 @@ var DEFAULT_AGENT_COMMAND = `node ${DEFAULT_AGENT_FILE}`;
4541
4580
  var MANIFEST_SCHEMA_URL = "https://pome.sh/schemas/v1/pome.json";
4542
4581
  var MAX_UNREADABLE_PATHS_SHOWN = 5;
4543
4582
  function readPackageVersion() {
4544
- if ("0.23.32".length > 0) return "0.23.32";
4583
+ if ("0.23.34".length > 0) return "0.23.34";
4545
4584
  try {
4546
4585
  const here = dirname(fileURLToPath(import.meta.url));
4547
4586
  const candidates = [
@@ -5034,7 +5073,7 @@ function createProgram() {
5034
5073
  taskForRuns.config.runs
5035
5074
  );
5036
5075
  if (k > 1) {
5037
- const { runTrialGroup } = await import('../../runTrialGroup-WXDRCVUE.js');
5076
+ const { runTrialGroup } = await import('../../runTrialGroup-VT7UGDJU.js');
5038
5077
  const fileForRerun = relative(process.cwd(), file);
5039
5078
  const rerunCommand = defaultTask ? options.trials !== void 0 ? `pome run -n ${k}` : "pome run" : `pome run ${fileForRerun && !fileForRerun.startsWith("..") ? fileForRerun : file} -n ${k}`;
5040
5079
  const groupResult = await runTrialGroup({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pome-sh/cli",
3
- "version": "0.23.32",
3
+ "version": "0.23.34",
4
4
  "description": "Digital-twin testing for AI agents \u2014 run tasks against resettable local or hosted twins and record tool-call traces for evaluation on pome.sh.",
5
5
  "keywords": [
6
6
  "ai",