@pome-sh/cli 0.42.4 → 0.43.1

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 (30) hide show
  1. package/README.md +238 -117
  2. package/dist/build-info.json +3 -3
  3. package/dist/{checks-BKMTBJSO.js → checks-V442KL5O.js} +9 -14
  4. package/dist/{chunk-RPPF2KDQ.js → chunk-4DXTT3RV.js} +7 -7
  5. package/dist/{chunk-6KJC4BTO.js → chunk-5KFDRR53.js} +2 -2
  6. package/dist/{chunk-5NPGY73F.js → chunk-64AWQJ7R.js} +2 -2
  7. package/dist/{chunk-STMGQ7GU.js → chunk-A6AM6KS4.js} +1405 -172
  8. package/dist/{chunk-NNXVR46L.js → chunk-CS7O2ZXB.js} +114 -2
  9. package/dist/{chunk-VPXIGCZW.js → chunk-GQSNU3YP.js} +1 -1
  10. package/dist/{chunk-HRAD7MRX.js → chunk-TWURH7YM.js} +34 -10
  11. package/dist/{runTrialGroup-BP446HIE.js → runTrialGroup-HYGGBLMM.js} +20 -10
  12. package/dist/{server-GDK4TBTL.js → server-2WHSHTUD.js} +2 -2
  13. package/dist/src/cli/main.js +488 -226
  14. package/dist/{src-Z4C4SSDR.js → src-DBOHIQNB.js} +2 -2
  15. package/dist/{src-FUPOFZI4.js → src-FRPUTB2H.js} +2 -2
  16. package/dist/{src-UY4Y75BD.js → src-G6CMFUR6.js} +2 -2
  17. package/dist/{src-SNSK5ENY.js → src-SJDGRXC5.js} +2 -2
  18. package/dist/{src-V3RUKDMQ.js → src-VBXONWR3.js} +2 -2
  19. package/dist/twinHarness-33MAVAXV.js +6 -0
  20. package/dist/{twinSeed-X6VHBOLM.js → twinSeed-J7UAY3GM.js} +1 -1
  21. package/dist/{twinStart-QQU6OIO4.js → twinStart-3Q74IURZ.js} +21 -17
  22. package/package.json +1 -2
  23. package/dist/agent-Q2UTRJYL.js +0 -408
  24. package/dist/chunk-46POYRLY.js +0 -1240
  25. package/dist/chunk-DFOQGAKS.js +0 -116
  26. package/dist/chunk-JNXZBK3O.js +0 -17
  27. package/dist/chunk-WERG4AUH.js +0 -462
  28. package/dist/chunk-ZX4WNSZ5.js +0 -71
  29. package/dist/runDemo-DRDMCG25.js +0 -408
  30. package/dist/twinHarness-ATYQTDA5.js +0 -6
@@ -1,8 +1,11 @@
1
1
  import { seedSchema as seedSchema$2 } from './chunk-NBOQN5VX.js';
2
2
  import { seedSchema } from './chunk-YBWG5JK2.js';
3
- import { twinIdSchema } from './chunk-6KJC4BTO.js';
3
+ import { twinIdSchema } from './chunk-5KFDRR53.js';
4
4
  import { seedSchema as seedSchema$1 } from './chunk-2K6BJ3PI.js';
5
5
  import { z } from 'zod';
6
+ import { readFile, writeFile } from 'node:fs/promises';
7
+ import { resolve, join, dirname } from 'node:path';
8
+ import { stringify, parse } from 'yaml';
6
9
 
7
10
  var SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
8
11
  var SLUG_MAX_LENGTH = 64;
@@ -1146,5 +1149,114 @@ function exitCodeFor(err) {
1146
1149
  if (err instanceof HostedDiscardRefusedError) return 5;
1147
1150
  return 2;
1148
1151
  }
1152
+ var MANIFEST_JSON = "pome.json";
1153
+ var MANIFEST_YAML = "pome.yaml";
1154
+ var MANIFEST_YML = "pome.yml";
1155
+ var MANIFEST_FILES = [MANIFEST_JSON, MANIFEST_YAML, MANIFEST_YML];
1156
+ var SCHEMA_URL = "https://pome.sh/schemas/v1/pome.json";
1157
+ var YAML_SCHEMA_COMMENT = `# yaml-language-server: $schema=${SCHEMA_URL}`;
1158
+ function formatFor(fileName) {
1159
+ return fileName === MANIFEST_JSON ? "json" : "yaml";
1160
+ }
1161
+ async function findManifestPath(startDir = process.cwd()) {
1162
+ let dir = resolve(startDir);
1163
+ for (; ; ) {
1164
+ const present = [];
1165
+ for (const fileName of MANIFEST_FILES) {
1166
+ if (await fileExists(join(dir, fileName))) present.push(fileName);
1167
+ }
1168
+ if (present.length > 1) {
1169
+ throw new HostedOrchError(
1170
+ `Multiple pome manifests in ${dir}: ${present.join(", ")}. Keep exactly one (pome.json is canonical).`
1171
+ );
1172
+ }
1173
+ if (present.length === 1) {
1174
+ const fileName = present[0];
1175
+ return { path: join(dir, fileName), format: formatFor(fileName) };
1176
+ }
1177
+ const parent = dirname(dir);
1178
+ if (parent === dir) return null;
1179
+ dir = parent;
1180
+ }
1181
+ }
1182
+ async function readManifest(startDir = process.cwd()) {
1183
+ const found = await findManifestPath(startDir);
1184
+ if (!found) return null;
1185
+ const text = await readFile(found.path, "utf8");
1186
+ const raw = parseManifestText(text, found);
1187
+ const manifest = validateManifest(raw, found.path);
1188
+ return { ...found, manifest, raw };
1189
+ }
1190
+ async function readRequiredManifest(startDir = process.cwd()) {
1191
+ const read = await readManifest(startDir);
1192
+ if (!read) {
1193
+ throw new HostedOrchError(
1194
+ `No pome manifest found (${MANIFEST_JSON} or ${MANIFEST_YAML}). Run \`pome init\` first.`
1195
+ );
1196
+ }
1197
+ return read;
1198
+ }
1199
+ async function writeManifest(path, format, data) {
1200
+ if (format === "json") {
1201
+ await writeFile(path, `${JSON.stringify(data, null, 2)}
1202
+ `);
1203
+ return;
1204
+ }
1205
+ const { $schema: _dropped, ...body } = data;
1206
+ await writeFile(path, `${YAML_SCHEMA_COMMENT}
1207
+ ${stringify(body)}`);
1208
+ }
1209
+ function parseManifestText(text, found) {
1210
+ let parsed;
1211
+ try {
1212
+ parsed = found.format === "json" ? JSON.parse(text) : parse(text);
1213
+ } catch (err) {
1214
+ throw new HostedOrchError(
1215
+ `${found.path} is not valid ${found.format.toUpperCase()}: ${err instanceof Error ? err.message : String(err)}`
1216
+ );
1217
+ }
1218
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
1219
+ throw new HostedOrchError(`${found.path} is not a ${found.format} object`);
1220
+ }
1221
+ return parsed;
1222
+ }
1223
+ function validateManifest(raw, path) {
1224
+ const result = manifestSchema.safeParse(raw);
1225
+ if (result.success) return result.data;
1226
+ const slugIssue = result.error.issues.find(
1227
+ (issue) => issue.path[0] === "agent" && issue.path[1] === "slug"
1228
+ );
1229
+ if (slugIssue) {
1230
+ throw new HostedOrchError(slugErrorMessage(raw, path));
1231
+ }
1232
+ const summary = result.error.issues.map((issue) => `${issue.path.join(".") || "(root)"}: ${issue.message}`).join("; ");
1233
+ throw new HostedOrchError(`Invalid pome manifest ${path}: ${summary}`);
1234
+ }
1235
+ function slugErrorMessage(raw, path) {
1236
+ const agent = typeof raw.agent === "object" && raw.agent !== null ? raw.agent : {};
1237
+ const name = typeof agent.name === "string" ? agent.name : "";
1238
+ const badSlug = typeof agent.slug === "string" ? agent.slug : "";
1239
+ const suggestion = deriveAgentSlug(name || badSlug);
1240
+ const base = `Invalid agent.slug in ${path}: must match ${SLUG_RE} (lowercase kebab-case, max 64 chars).`;
1241
+ return suggestion.length > 0 ? `${base} Did you mean "${suggestion}"?` : base;
1242
+ }
1243
+ function normalizeManifestTwins(manifestTwins) {
1244
+ if (manifestTwins === void 0) return void 0;
1245
+ const out = /* @__PURE__ */ new Set();
1246
+ for (const twin of manifestTwins) {
1247
+ const norm = twin.trim().toLowerCase();
1248
+ if (norm.length > 0) out.add(norm);
1249
+ }
1250
+ return out.size > 0 ? [...out] : void 0;
1251
+ }
1252
+ async function fileExists(path) {
1253
+ try {
1254
+ await readFile(path, "utf8");
1255
+ return true;
1256
+ } catch (err) {
1257
+ if (err.code === "ENOENT") return false;
1258
+ throw err;
1259
+ }
1260
+ }
1149
1261
 
1150
- export { HostedAuthError, HostedDiscardRefusedError, HostedOrchError, HostedQuotaError, HostedTrialError, HostedUsageError, MOUNTED_TWINS, SLUG_RE, agentResponseSchema, createEvalSessionResponseSchema, createSessionResponseSchema, criterionSchema, deriveAgentSlug, exitCodeFor, finalizeResponseSchema, isMultiTwinSeedEnvelope, manifestSchema, normalizeTaskConfigKeys, sessionPublicSchema, submitResultResponseSchema };
1262
+ export { HostedAuthError, HostedDiscardRefusedError, HostedOrchError, HostedQuotaError, HostedTrialError, HostedUsageError, MANIFEST_JSON, MOUNTED_TWINS, agentResponseSchema, createEvalSessionResponseSchema, createSessionResponseSchema, criterionSchema, deriveAgentSlug, exitCodeFor, finalizeResponseSchema, findManifestPath, isMultiTwinSeedEnvelope, normalizeManifestTwins, normalizeTaskConfigKeys, readManifest, readRequiredManifest, sessionPublicSchema, submitResultResponseSchema, writeManifest };
@@ -1,4 +1,4 @@
1
- import { isTwinName, TWIN_REGISTRY, TWIN_NAMES } from './chunk-RPPF2KDQ.js';
1
+ import { isTwinName, TWIN_REGISTRY, TWIN_NAMES } from './chunk-4DXTT3RV.js';
2
2
  import { readFileSync } from 'node:fs';
3
3
  import { parse } from 'yaml';
4
4
 
@@ -445,6 +445,7 @@ function defineTwin(spec) {
445
445
  }
446
446
  var RESERVED_SESSION_PREFIXES = ["/_pome", "/mcp"];
447
447
  var CLIENT_IP_VAR = "pomeClientIp";
448
+ var ADMIN_NO_PEER_OPT_IN = "TWIN_ADMIN_ALLOW_NO_PEER";
448
449
  var nodeGetConnInfo;
449
450
  function loadNodeGetConnInfo() {
450
451
  nodeGetConnInfo ??= import('@hono/node-server/conninfo').then((mod) => mod.getConnInfo, () => void 0);
@@ -490,10 +491,11 @@ function createAdminGate(options = {}) {
490
491
  }
491
492
  const remote = await getClientIp(c);
492
493
  if (!remote) {
493
- if (process.env.NODE_ENV === "production")
494
- return forbidden();
495
- await next();
496
- return;
494
+ if (process.env[ADMIN_NO_PEER_OPT_IN] === "1") {
495
+ await next();
496
+ return;
497
+ }
498
+ return forbidden();
497
499
  }
498
500
  if (!isLoopbackAddress(remote))
499
501
  return forbidden();
@@ -503,13 +505,22 @@ function createAdminGate(options = {}) {
503
505
 
504
506
  // ../packages/sdk/dist/auth.js
505
507
  var PROVIDER_SHAPED_TEAM_ID = "provider-shaped";
508
+ var DEV_ONLY_INSECURE_SECRET = "dev-only-insecure-secret";
509
+ var DEV_SECRETS_OPT_IN = "POME_ALLOW_DEV_SECRETS";
506
510
  function resolveAuthSecret() {
507
511
  const secret = process.env.TWIN_AUTH_SECRET;
508
- if (!secret && process.env.NODE_ENV === "production") {
509
- throw new Error("TWIN_AUTH_SECRET required in production");
510
- }
511
- return secret ?? "dev-only-insecure-secret";
512
+ if (secret)
513
+ return secret;
514
+ if (process.env[DEV_SECRETS_OPT_IN] === "1")
515
+ return DEV_ONLY_INSECURE_SECRET;
516
+ throw new MissingAuthSecretError();
512
517
  }
518
+ var MissingAuthSecretError = class extends Error {
519
+ constructor() {
520
+ super(`TWIN_AUTH_SECRET is not set. Set it, or set ${DEV_SECRETS_OPT_IN}=1 to serve the public dev secret on a twin nothing but this machine can reach.`);
521
+ this.name = "MissingAuthSecretError";
522
+ }
523
+ };
513
524
  var SIG_LENGTH = 22;
514
525
  function mintProviderToken(spec, options) {
515
526
  const prefix = options.prefix ?? spec.prefixes[0];
@@ -674,7 +685,14 @@ function bearerAuth(options = {}) {
674
685
  }
675
686
  }
676
687
  if (options.providerToken) {
677
- const providerSid = verifyProviderToken(options.providerToken, token);
688
+ let providerSid;
689
+ try {
690
+ providerSid = verifyProviderToken(options.providerToken, token);
691
+ } catch (err) {
692
+ if (err instanceof MissingAuthSecretError)
693
+ return respond(unauthorized("invalid", { token }));
694
+ throw err;
695
+ }
678
696
  if (providerSid) {
679
697
  const mismatch2 = checkSid(providerSid);
680
698
  if (mismatch2)
@@ -1281,8 +1299,14 @@ function isLoopbackHost(value) {
1281
1299
  function ensureTwinAuthSecret(twin, host) {
1282
1300
  if (process.env.TWIN_AUTH_SECRET)
1283
1301
  return;
1284
- if (isLoopbackHost(host))
1302
+ if (isLoopbackHost(host)) {
1303
+ if (process.env[DEV_SECRETS_OPT_IN] === "1")
1304
+ return;
1305
+ const secret = randomBytes(32).toString("hex");
1306
+ process.env.TWIN_AUTH_SECRET = secret;
1307
+ console.log(`[twin-${twin}] TWIN_AUTH_SECRET not set \u2014 generated ${secret} for this loopback boot (not persisted; set TWIN_AUTH_SECRET to choose one, or ${DEV_SECRETS_OPT_IN}=1 for the public dev secret)`);
1285
1308
  return;
1309
+ }
1286
1310
  const dataDir = process.env.POME_TWIN_DATA_DIR || join(".pome-data", twin);
1287
1311
  const secretPath = join(dataDir, "secret");
1288
1312
  try {
@@ -1,24 +1,34 @@
1
- import { newGroupId } from './chunk-JNXZBK3O.js';
2
- import { runTaskHosted, resolveRunAgentIdentity } from './chunk-46POYRLY.js';
3
- import { createHostedClient, parseTaskFile, outcomeOf, isNarrated, criterionPhrase, narratorReadingLines } from './chunk-STMGQ7GU.js';
4
- import './chunk-VPXIGCZW.js';
1
+ import { runTaskHosted, createHostedClient, parseTaskFile, resolveRunAgentIdentity, outcomeOf, isNarrated, criterionPhrase, narratorReadingLines } from './chunk-A6AM6KS4.js';
2
+ import './chunk-GQSNU3YP.js';
5
3
  import './chunk-NW7HGA2K.js';
6
4
  import './chunk-PASFBRK4.js';
7
5
  import './chunk-3FZY376K.js';
8
- import './chunk-RPPF2KDQ.js';
9
- import './chunk-DFOQGAKS.js';
10
- import { HostedQuotaError, HostedTrialError } from './chunk-NNXVR46L.js';
6
+ import './chunk-4DXTT3RV.js';
7
+ import { HostedQuotaError, HostedTrialError } from './chunk-CS7O2ZXB.js';
11
8
  import './chunk-NBOQN5VX.js';
12
9
  import './chunk-YBWG5JK2.js';
13
- import './chunk-HRAD7MRX.js';
14
- import './chunk-6KJC4BTO.js';
10
+ import './chunk-TWURH7YM.js';
11
+ import './chunk-5KFDRR53.js';
15
12
  import './chunk-SG6ZTIMT.js';
16
13
  import './chunk-2K6BJ3PI.js';
17
14
  import './chunk-FBSA5L36.js';
18
- import { randomUUID } from 'node:crypto';
15
+ import { randomUUID, randomBytes } from 'node:crypto';
19
16
  import { readFile } from 'node:fs/promises';
20
17
  import { dirname } from 'node:path';
21
18
 
19
+ var NANOID_ALPHABET = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
20
+ function nanoid(size = 21) {
21
+ const bytes = randomBytes(size);
22
+ let id = "";
23
+ for (let i = 0; i < size; i += 1) {
24
+ id += NANOID_ALPHABET[bytes[i] & 63];
25
+ }
26
+ return id;
27
+ }
28
+ function newGroupId() {
29
+ return `grp_${nanoid(21)}`;
30
+ }
31
+
22
32
  // src/runner/groupRender.ts
23
33
  function flagHintLine(agentCommandSource) {
24
34
  return `-n sets how many isolated trials to run \xB7 the agent command comes from ${agentCommandSource}`;
@@ -1,4 +1,4 @@
1
- export { POME_RECORDER_EVENTS_PATH, PROVIDER_SHAPED_TEAM_ID, TwinBootError, TwinError, UnknownToolError, bearerAuth, createAdminGate, createApp, createFileBackedRecorderStore, createRecorderHandle, createRecorderStore, created, ensureTwinAuthSecret, failureInjectionMiddleware, formTokenResolver, isLoopbackHost, mintProviderToken, ok, queryTokenResolver, recordedRequestHeaders, requireAdminAuth, resolveAuthSecret, resolveRecorderStore, serve, setClientIp, setRecordedTool, toTwinHttpEventRow, twinBuildInfo, verifyProviderToken } from './chunk-HRAD7MRX.js';
2
- import './chunk-6KJC4BTO.js';
1
+ export { POME_RECORDER_EVENTS_PATH, PROVIDER_SHAPED_TEAM_ID, TwinBootError, TwinError, UnknownToolError, bearerAuth, createAdminGate, createApp, createFileBackedRecorderStore, createRecorderHandle, createRecorderStore, created, ensureTwinAuthSecret, failureInjectionMiddleware, formTokenResolver, isLoopbackHost, mintProviderToken, ok, queryTokenResolver, recordedRequestHeaders, requireAdminAuth, resolveAuthSecret, resolveRecorderStore, serve, setClientIp, setRecordedTool, toTwinHttpEventRow, twinBuildInfo, verifyProviderToken } from './chunk-TWURH7YM.js';
2
+ import './chunk-5KFDRR53.js';
3
3
  export { redactEvent, redactSecrets } from './chunk-SG6ZTIMT.js';
4
4
  export { FAILURE_INJECTION_OVERRIDE_KEY, createFailureInjectionStore, failureInjectionRuleSchema } from './chunk-FBSA5L36.js';