@pome-sh/cli 0.43.1 → 0.45.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.
- package/README.md +1 -1
- package/dist/build-info.json +3 -3
- package/dist/{checks-V442KL5O.js → checks-RDU56OGI.js} +4 -3
- package/dist/chunk-26UAPLHK.js +191 -0
- package/dist/chunk-4LQ4IJOC.js +1 -0
- package/dist/{chunk-5KFDRR53.js → chunk-7VZBAHQ2.js} +2 -2
- package/dist/chunk-AGZOWSLG.js +142 -0
- package/dist/{chunk-4DXTT3RV.js → chunk-BXYPNEJY.js} +7 -7
- package/dist/{chunk-GQSNU3YP.js → chunk-DX2KCFJM.js} +1 -1
- package/dist/{chunk-64AWQJ7R.js → chunk-EZYVICDB.js} +1 -1
- package/dist/{chunk-A6AM6KS4.js → chunk-HEEFOMSZ.js} +11 -70
- package/dist/{chunk-CS7O2ZXB.js → chunk-M7ATJ423.js} +5 -190
- package/dist/{runTrialGroup-HYGGBLMM.js → runTrialGroup-MMTTTDWY.js} +7 -5
- package/dist/{server-2WHSHTUD.js → server-GECKG2H6.js} +1 -1
- package/dist/src/cli/main.js +246 -174
- package/dist/{src-G6CMFUR6.js → src-46YGR2WY.js} +1 -7
- package/dist/{src-DBOHIQNB.js → src-CV7QDV5E.js} +1 -1
- package/dist/{src-FRPUTB2H.js → src-D3PKLT54.js} +1 -1
- package/dist/{src-SJDGRXC5.js → src-LPTWNBO5.js} +1 -1
- package/dist/{src-VBXONWR3.js → src-STAXYPD3.js} +18 -2
- package/dist/twinHarness-I2JGKQYD.js +6 -0
- package/dist/{twinSeed-J7UAY3GM.js → twinSeed-ZFZO7BL7.js} +1 -1
- package/dist/twinStart-XN3BYOUF.js +422 -0
- package/dist/twinTape-5P3HQ27N.js +418 -0
- package/examples/agents/mcp-loop-agent.ts +0 -6
- package/package.json +30 -24
- package/dist/twinHarness-33MAVAXV.js +0 -6
- package/dist/twinStart-3Q74IURZ.js +0 -187
package/README.md
CHANGED
|
@@ -142,6 +142,7 @@ Global hosted configuration:
|
|
|
142
142
|
| `POME_API_KEY` | Authenticate hosted commands. This value takes precedence over stored credentials. |
|
|
143
143
|
| `POME_API_URL` | Set the control-plane URL. `--api-url` takes precedence. |
|
|
144
144
|
| `POME_DASHBOARD_URL` | Set the dashboard URL for login and result links. |
|
|
145
|
+
| `POME_TELEMETRY=0` | Turn off the anonymous daily usage event (one per day at most: CLI version, OS, Node major, command name; never arguments, paths or repo names). `DO_NOT_TRACK=1` is honoured too, and nothing is sent when `CI` is set. |
|
|
145
146
|
|
|
146
147
|
Agent process configuration:
|
|
147
148
|
|
|
@@ -202,7 +203,6 @@ A run can also contain these files:
|
|
|
202
203
|
|
|
203
204
|
| File | Condition |
|
|
204
205
|
| --- | --- |
|
|
205
|
-
| `signals.jsonl` | The runner creates this adapter-event sidecar. |
|
|
206
206
|
| `egress.jsonl` | The capture proxy records refused connections here. |
|
|
207
207
|
| `state_final.<twin>.json` | A multi-twin run records each additional final state. |
|
|
208
208
|
| `verdict.json` | A hosted `pome run` caches the hosted verdict for `pome fix-prompt`. |
|
package/dist/build-info.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"package": "pome-sh",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"git_sha": "
|
|
5
|
-
"build_time": "2026-09-
|
|
3
|
+
"version": "0.45.0",
|
|
4
|
+
"git_sha": "16bd8bf4255ab4a22c0d466529abcab652301773",
|
|
5
|
+
"build_time": "2026-09-16T19:32:06.710Z"
|
|
6
6
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { getAvailablePort } from './chunk-XDU6TD4O.js';
|
|
2
|
-
import { findManifestPath, readManifest } from './chunk-
|
|
2
|
+
import { findManifestPath, readManifest } from './chunk-26UAPLHK.js';
|
|
3
|
+
import './chunk-M7ATJ423.js';
|
|
3
4
|
import { buildEgressAllowlist } from './chunk-CBFKZZBR.js';
|
|
4
5
|
import './chunk-NBOQN5VX.js';
|
|
5
6
|
import './chunk-YBWG5JK2.js';
|
|
6
|
-
import './chunk-
|
|
7
|
+
import './chunk-7VZBAHQ2.js';
|
|
7
8
|
import './chunk-SG6ZTIMT.js';
|
|
8
9
|
import './chunk-2K6BJ3PI.js';
|
|
9
10
|
import './chunk-FBSA5L36.js';
|
|
@@ -182,7 +183,7 @@ async function checkTwinReachable(_configDir) {
|
|
|
182
183
|
});
|
|
183
184
|
let harness;
|
|
184
185
|
try {
|
|
185
|
-
const { bootTwin } = await import('./twinHarness-
|
|
186
|
+
const { bootTwin } = await import('./twinHarness-I2JGKQYD.js');
|
|
186
187
|
harness = await bootTwin({
|
|
187
188
|
twin: "github",
|
|
188
189
|
seedState: void 0,
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { manifestSchema, deriveAgentSlug, SLUG_RE } from './chunk-M7ATJ423.js';
|
|
2
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { resolve, join, dirname } from 'node:path';
|
|
4
|
+
import { stringify, parse } from 'yaml';
|
|
5
|
+
|
|
6
|
+
// src/hosted/errors.ts
|
|
7
|
+
var HostedAuthError = class extends Error {
|
|
8
|
+
constructor(message, requestId) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.requestId = requestId;
|
|
11
|
+
this.name = "HostedAuthError";
|
|
12
|
+
}
|
|
13
|
+
requestId;
|
|
14
|
+
};
|
|
15
|
+
var HostedQuotaError = class extends Error {
|
|
16
|
+
/** `details` mirrors the cloud error envelope's machine-readable details
|
|
17
|
+
* (e.g. `{ kind: "daily_judge_cap" }`) so `pome demo` can
|
|
18
|
+
* render honest labeled at-capacity states. Optional: older responses and
|
|
19
|
+
* the twin-pod 401 shape carry none. */
|
|
20
|
+
constructor(message, requestId, details) {
|
|
21
|
+
super(message);
|
|
22
|
+
this.requestId = requestId;
|
|
23
|
+
this.details = details;
|
|
24
|
+
this.name = "HostedQuotaError";
|
|
25
|
+
}
|
|
26
|
+
requestId;
|
|
27
|
+
details;
|
|
28
|
+
};
|
|
29
|
+
var HostedOrchError = class extends Error {
|
|
30
|
+
/** `status` is the HTTP status that produced this error, when one exists
|
|
31
|
+
* (network/parse failures leave it undefined). `pome eval` uses it to
|
|
32
|
+
* scope its reaped-session retry to 404/410 only. */
|
|
33
|
+
constructor(message, requestId, status, type) {
|
|
34
|
+
super(message);
|
|
35
|
+
this.requestId = requestId;
|
|
36
|
+
this.status = status;
|
|
37
|
+
this.type = type;
|
|
38
|
+
this.name = "HostedOrchError";
|
|
39
|
+
}
|
|
40
|
+
requestId;
|
|
41
|
+
status;
|
|
42
|
+
type;
|
|
43
|
+
};
|
|
44
|
+
var HostedUsageError = class extends Error {
|
|
45
|
+
constructor(message) {
|
|
46
|
+
super(message);
|
|
47
|
+
this.name = "HostedUsageError";
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
var HostedTrialError = class extends Error {
|
|
51
|
+
constructor(message, errorCode) {
|
|
52
|
+
super(message);
|
|
53
|
+
this.errorCode = errorCode;
|
|
54
|
+
this.name = "HostedTrialError";
|
|
55
|
+
}
|
|
56
|
+
errorCode;
|
|
57
|
+
};
|
|
58
|
+
var HostedDiscardRefusedError = class extends Error {
|
|
59
|
+
constructor(message, sessionId, state, taskName, openSeconds, discardToken) {
|
|
60
|
+
super(message);
|
|
61
|
+
this.sessionId = sessionId;
|
|
62
|
+
this.state = state;
|
|
63
|
+
this.taskName = taskName;
|
|
64
|
+
this.openSeconds = openSeconds;
|
|
65
|
+
this.discardToken = discardToken;
|
|
66
|
+
this.name = "HostedDiscardRefusedError";
|
|
67
|
+
}
|
|
68
|
+
sessionId;
|
|
69
|
+
state;
|
|
70
|
+
taskName;
|
|
71
|
+
openSeconds;
|
|
72
|
+
discardToken;
|
|
73
|
+
};
|
|
74
|
+
function exitCodeFor(err) {
|
|
75
|
+
if (err instanceof HostedAuthError) return 3;
|
|
76
|
+
if (err instanceof HostedQuotaError) return 4;
|
|
77
|
+
if (err instanceof HostedUsageError) return 5;
|
|
78
|
+
if (err instanceof HostedDiscardRefusedError) return 5;
|
|
79
|
+
return 2;
|
|
80
|
+
}
|
|
81
|
+
var MANIFEST_JSON = "pome.json";
|
|
82
|
+
var MANIFEST_YAML = "pome.yaml";
|
|
83
|
+
var MANIFEST_YML = "pome.yml";
|
|
84
|
+
var MANIFEST_FILES = [MANIFEST_JSON, MANIFEST_YAML, MANIFEST_YML];
|
|
85
|
+
var SCHEMA_URL = "https://pome.sh/schemas/v1/pome.json";
|
|
86
|
+
var YAML_SCHEMA_COMMENT = `# yaml-language-server: $schema=${SCHEMA_URL}`;
|
|
87
|
+
function formatFor(fileName) {
|
|
88
|
+
return fileName === MANIFEST_JSON ? "json" : "yaml";
|
|
89
|
+
}
|
|
90
|
+
async function findManifestPath(startDir = process.cwd()) {
|
|
91
|
+
let dir = resolve(startDir);
|
|
92
|
+
for (; ; ) {
|
|
93
|
+
const present = [];
|
|
94
|
+
for (const fileName of MANIFEST_FILES) {
|
|
95
|
+
if (await fileExists(join(dir, fileName))) present.push(fileName);
|
|
96
|
+
}
|
|
97
|
+
if (present.length > 1) {
|
|
98
|
+
throw new HostedOrchError(
|
|
99
|
+
`Multiple pome manifests in ${dir}: ${present.join(", ")}. Keep exactly one (pome.json is canonical).`
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
if (present.length === 1) {
|
|
103
|
+
const fileName = present[0];
|
|
104
|
+
return { path: join(dir, fileName), format: formatFor(fileName) };
|
|
105
|
+
}
|
|
106
|
+
const parent = dirname(dir);
|
|
107
|
+
if (parent === dir) return null;
|
|
108
|
+
dir = parent;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
async function readManifest(startDir = process.cwd()) {
|
|
112
|
+
const found = await findManifestPath(startDir);
|
|
113
|
+
if (!found) return null;
|
|
114
|
+
const text = await readFile(found.path, "utf8");
|
|
115
|
+
const raw = parseManifestText(text, found);
|
|
116
|
+
const manifest = validateManifest(raw, found.path);
|
|
117
|
+
return { ...found, manifest, raw };
|
|
118
|
+
}
|
|
119
|
+
async function readRequiredManifest(startDir = process.cwd()) {
|
|
120
|
+
const read = await readManifest(startDir);
|
|
121
|
+
if (!read) {
|
|
122
|
+
throw new HostedOrchError(
|
|
123
|
+
`No pome manifest found (${MANIFEST_JSON} or ${MANIFEST_YAML}). Run \`pome init\` first.`
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
return read;
|
|
127
|
+
}
|
|
128
|
+
async function writeManifest(path, format, data) {
|
|
129
|
+
if (format === "json") {
|
|
130
|
+
await writeFile(path, `${JSON.stringify(data, null, 2)}
|
|
131
|
+
`);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const { $schema: _dropped, ...body } = data;
|
|
135
|
+
await writeFile(path, `${YAML_SCHEMA_COMMENT}
|
|
136
|
+
${stringify(body)}`);
|
|
137
|
+
}
|
|
138
|
+
function parseManifestText(text, found) {
|
|
139
|
+
let parsed;
|
|
140
|
+
try {
|
|
141
|
+
parsed = found.format === "json" ? JSON.parse(text) : parse(text);
|
|
142
|
+
} catch (err) {
|
|
143
|
+
throw new HostedOrchError(
|
|
144
|
+
`${found.path} is not valid ${found.format.toUpperCase()}: ${err instanceof Error ? err.message : String(err)}`
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
148
|
+
throw new HostedOrchError(`${found.path} is not a ${found.format} object`);
|
|
149
|
+
}
|
|
150
|
+
return parsed;
|
|
151
|
+
}
|
|
152
|
+
function validateManifest(raw, path) {
|
|
153
|
+
const result = manifestSchema.safeParse(raw);
|
|
154
|
+
if (result.success) return result.data;
|
|
155
|
+
const slugIssue = result.error.issues.find(
|
|
156
|
+
(issue) => issue.path[0] === "agent" && issue.path[1] === "slug"
|
|
157
|
+
);
|
|
158
|
+
if (slugIssue) {
|
|
159
|
+
throw new HostedOrchError(slugErrorMessage(raw, path));
|
|
160
|
+
}
|
|
161
|
+
const summary = result.error.issues.map((issue) => `${issue.path.join(".") || "(root)"}: ${issue.message}`).join("; ");
|
|
162
|
+
throw new HostedOrchError(`Invalid pome manifest ${path}: ${summary}`);
|
|
163
|
+
}
|
|
164
|
+
function slugErrorMessage(raw, path) {
|
|
165
|
+
const agent = typeof raw.agent === "object" && raw.agent !== null ? raw.agent : {};
|
|
166
|
+
const name = typeof agent.name === "string" ? agent.name : "";
|
|
167
|
+
const badSlug = typeof agent.slug === "string" ? agent.slug : "";
|
|
168
|
+
const suggestion = deriveAgentSlug(name || badSlug);
|
|
169
|
+
const base = `Invalid agent.slug in ${path}: must match ${SLUG_RE} (lowercase kebab-case, max 64 chars).`;
|
|
170
|
+
return suggestion.length > 0 ? `${base} Did you mean "${suggestion}"?` : base;
|
|
171
|
+
}
|
|
172
|
+
function normalizeManifestTwins(manifestTwins) {
|
|
173
|
+
if (manifestTwins === void 0) return void 0;
|
|
174
|
+
const out = /* @__PURE__ */ new Set();
|
|
175
|
+
for (const twin of manifestTwins) {
|
|
176
|
+
const norm = twin.trim().toLowerCase();
|
|
177
|
+
if (norm.length > 0) out.add(norm);
|
|
178
|
+
}
|
|
179
|
+
return out.size > 0 ? [...out] : void 0;
|
|
180
|
+
}
|
|
181
|
+
async function fileExists(path) {
|
|
182
|
+
try {
|
|
183
|
+
await readFile(path, "utf8");
|
|
184
|
+
return true;
|
|
185
|
+
} catch (err) {
|
|
186
|
+
if (err.code === "ENOENT") return false;
|
|
187
|
+
throw err;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export { HostedAuthError, HostedDiscardRefusedError, HostedOrchError, HostedQuotaError, HostedTrialError, HostedUsageError, MANIFEST_JSON, exitCodeFor, findManifestPath, normalizeManifestTwins, readManifest, readRequiredManifest, writeManifest };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -104,7 +104,7 @@ function normalizeHookCausingToolUseId(event) {
|
|
|
104
104
|
parent_event_id: null
|
|
105
105
|
};
|
|
106
106
|
}
|
|
107
|
-
recorderEventObjectSchema.transform(normalizeTaskStepVocab);
|
|
107
|
+
var recorderEventSchema = recorderEventObjectSchema.transform(normalizeTaskStepVocab);
|
|
108
108
|
var eventBaseShape = {
|
|
109
109
|
ts: z.string().datetime(),
|
|
110
110
|
event_id: z.string().min(1),
|
|
@@ -434,4 +434,4 @@ z.object({
|
|
|
434
434
|
});
|
|
435
435
|
z.union([eventSchema, otelSpanEventSchema]);
|
|
436
436
|
|
|
437
|
-
export { eventSchema, isLegacyEventRow, twinIdSchema };
|
|
437
|
+
export { eventSchema, isLegacyEventRow, recorderEventSchema, twinIdSchema };
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { mkdir, writeFile, rename, chmod, readFile, unlink, open, stat } from 'node:fs/promises';
|
|
2
|
+
import { dirname, join, basename } from 'node:path';
|
|
3
|
+
|
|
4
|
+
// src/twin/twinStatusFile.ts
|
|
5
|
+
var STANDALONE_STATUS_PATH = ".pome/twin-status.json";
|
|
6
|
+
async function writeStandaloneStatusFile(status, path = STANDALONE_STATUS_PATH) {
|
|
7
|
+
await mkdir(dirname(path), { recursive: true, mode: 448 });
|
|
8
|
+
const tmp = `${path}.${process.pid}.${Date.now()}.tmp`;
|
|
9
|
+
await writeFile(tmp, JSON.stringify(status, null, 2), { mode: 384 });
|
|
10
|
+
await rename(tmp, path);
|
|
11
|
+
await chmod(path, 384);
|
|
12
|
+
}
|
|
13
|
+
async function ensureSelfIgnoring(dir) {
|
|
14
|
+
if (basename(dir) !== ".pome") return;
|
|
15
|
+
const path = join(dir, ".gitignore");
|
|
16
|
+
try {
|
|
17
|
+
await writeFile(path, "*\n", { flag: "wx", mode: 384 });
|
|
18
|
+
} catch (err) {
|
|
19
|
+
if (err.code !== "EEXIST") throw err;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
var STALE_LOCK_MS = 1e4;
|
|
23
|
+
async function withStatusLock(path, fn) {
|
|
24
|
+
const lockPath = `${path}.lock`;
|
|
25
|
+
const deadline = Date.now() + 5e3;
|
|
26
|
+
for (; ; ) {
|
|
27
|
+
try {
|
|
28
|
+
const handle = await open(lockPath, "wx", 384);
|
|
29
|
+
try {
|
|
30
|
+
await handle.writeFile(String(process.pid));
|
|
31
|
+
} finally {
|
|
32
|
+
await handle.close();
|
|
33
|
+
}
|
|
34
|
+
break;
|
|
35
|
+
} catch (err) {
|
|
36
|
+
if (err.code !== "EEXIST") throw err;
|
|
37
|
+
const age = await stat(lockPath).then((s) => Date.now() - s.mtimeMs, () => 0);
|
|
38
|
+
if (age > STALE_LOCK_MS) {
|
|
39
|
+
await unlink(lockPath).catch(() => void 0);
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (Date.now() > deadline) {
|
|
43
|
+
throw new Error(
|
|
44
|
+
`pome twin start: ${lockPath} is held by another pome process \u2014 if none is running, delete it.`
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
return await fn();
|
|
52
|
+
} finally {
|
|
53
|
+
await unlink(lockPath).catch(() => void 0);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async function updateStandaloneStatusFile(entries, path = STANDALONE_STATUS_PATH) {
|
|
57
|
+
await mkdir(dirname(path), { recursive: true, mode: 448 });
|
|
58
|
+
await ensureSelfIgnoring(dirname(path));
|
|
59
|
+
return await withStatusLock(path, async () => {
|
|
60
|
+
const merged = mergeStandaloneStatus(await readStandaloneStatusFile(path), entries);
|
|
61
|
+
await writeStandaloneStatusFile(merged, path);
|
|
62
|
+
return merged;
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
function isStatusEntry(value) {
|
|
66
|
+
if (value === null || typeof value !== "object") return false;
|
|
67
|
+
const entry = value;
|
|
68
|
+
return typeof entry.name === "string" && typeof entry.url === "string" && typeof entry.rest_url === "string" && typeof entry.mcp_url === "string" && typeof entry.auth_token === "string";
|
|
69
|
+
}
|
|
70
|
+
function standaloneStatusEntries(contents) {
|
|
71
|
+
if (contents === null || typeof contents !== "object") return [];
|
|
72
|
+
const file = contents;
|
|
73
|
+
if (file.twins !== null && typeof file.twins === "object") {
|
|
74
|
+
return Object.values(file.twins).filter(isStatusEntry);
|
|
75
|
+
}
|
|
76
|
+
return isStatusEntry(file) ? [pick(file)] : [];
|
|
77
|
+
}
|
|
78
|
+
function pick(entry) {
|
|
79
|
+
return {
|
|
80
|
+
name: entry.name,
|
|
81
|
+
url: entry.url,
|
|
82
|
+
rest_url: entry.rest_url,
|
|
83
|
+
mcp_url: entry.mcp_url,
|
|
84
|
+
auth_token: entry.auth_token
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function mergeStandaloneStatus(existing, entries) {
|
|
88
|
+
const twins = {};
|
|
89
|
+
for (const entry of standaloneStatusEntries(existing)) twins[entry.name] = pick(entry);
|
|
90
|
+
for (const entry of entries) twins[entry.name] = pick(entry);
|
|
91
|
+
const first = entries[0];
|
|
92
|
+
if (first === void 0) throw new Error("mergeStandaloneStatus: no entries to write");
|
|
93
|
+
return { ...pick(first), twins };
|
|
94
|
+
}
|
|
95
|
+
async function readStandaloneStatusFile(path = STANDALONE_STATUS_PATH) {
|
|
96
|
+
try {
|
|
97
|
+
return JSON.parse(await readFile(path, "utf8"));
|
|
98
|
+
} catch {
|
|
99
|
+
return void 0;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
var STANDALONE_STATE_DIR = ".pome/twin-state";
|
|
103
|
+
function standaloneInitialStatePath(name, dir = STANDALONE_STATE_DIR) {
|
|
104
|
+
return join(dir, `${name}.initial.json`);
|
|
105
|
+
}
|
|
106
|
+
async function writeStandaloneInitialState(name, state, dir = STANDALONE_STATE_DIR) {
|
|
107
|
+
const path = standaloneInitialStatePath(name, dir);
|
|
108
|
+
await mkdir(dir, { recursive: true, mode: 448 });
|
|
109
|
+
const tmp = `${path}.${process.pid}.tmp`;
|
|
110
|
+
await writeFile(tmp, JSON.stringify(state), { mode: 384 });
|
|
111
|
+
await rename(tmp, path);
|
|
112
|
+
await chmod(path, 384);
|
|
113
|
+
}
|
|
114
|
+
async function readStandaloneInitialState(name, dir = STANDALONE_STATE_DIR) {
|
|
115
|
+
const path = standaloneInitialStatePath(name, dir);
|
|
116
|
+
let raw;
|
|
117
|
+
try {
|
|
118
|
+
raw = await readFile(path, "utf8");
|
|
119
|
+
} catch (err) {
|
|
120
|
+
if (err.code === "ENOENT") return void 0;
|
|
121
|
+
throw err;
|
|
122
|
+
}
|
|
123
|
+
try {
|
|
124
|
+
return JSON.parse(raw);
|
|
125
|
+
} catch {
|
|
126
|
+
throw new Error(`pome twin tape: ${path} is not valid JSON \u2014 restart the twin to rewrite it.`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
async function snapshotStandaloneInitialState(name, exportState, dir = STANDALONE_STATE_DIR) {
|
|
130
|
+
await unlink(standaloneInitialStatePath(name, dir)).catch((err) => {
|
|
131
|
+
if (err.code !== "ENOENT") throw err;
|
|
132
|
+
});
|
|
133
|
+
try {
|
|
134
|
+
await writeStandaloneInitialState(name, await exportState(), dir);
|
|
135
|
+
} catch (err) {
|
|
136
|
+
console.error(
|
|
137
|
+
`pome twin start: could not snapshot the ${name} twin's state for \`pome twin tape --diff\`: ${err.message}`
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export { STANDALONE_STATUS_PATH, mergeStandaloneStatus, readStandaloneInitialState, readStandaloneStatusFile, snapshotStandaloneInitialState, standaloneInitialStatePath, standaloneStatusEntries, updateStandaloneStatusFile, writeStandaloneStatusFile };
|
|
@@ -39,7 +39,7 @@ var TWIN_REGISTRY = {
|
|
|
39
39
|
defaultSeedState,
|
|
40
40
|
GitHubDomain,
|
|
41
41
|
openGitHubCloneDatabase
|
|
42
|
-
} = await import('./src-
|
|
42
|
+
} = await import('./src-46YGR2WY.js');
|
|
43
43
|
const db = openGitHubCloneDatabase();
|
|
44
44
|
const domain = new GitHubDomain(db);
|
|
45
45
|
domain.seed(seedState === void 0 ? defaultSeedState() : seedState);
|
|
@@ -63,7 +63,7 @@ var TWIN_REGISTRY = {
|
|
|
63
63
|
parseSeed: async (input) => (await import('./seed-SYJXLGWF.js')).parseSeed(input),
|
|
64
64
|
seedFields: async () => Object.keys((await import('./seed-SYJXLGWF.js')).seedSchema.shape),
|
|
65
65
|
async boot({ seedState, runId, recorder }) {
|
|
66
|
-
const { createSlackTwinApp, openSlackTwinDatabase, SlackDomain } = await import('./src-
|
|
66
|
+
const { createSlackTwinApp, openSlackTwinDatabase, SlackDomain } = await import('./src-LPTWNBO5.js');
|
|
67
67
|
const db = openSlackTwinDatabase(":memory:");
|
|
68
68
|
const domain = new SlackDomain(db);
|
|
69
69
|
domain.applySeed(seedState);
|
|
@@ -90,8 +90,8 @@ var TWIN_REGISTRY = {
|
|
|
90
90
|
parseSeed: async (input) => (await import('./seed-E6SA4NKZ.js')).parseSeed(input),
|
|
91
91
|
seedFields: async () => Object.keys((await import('./seed-E6SA4NKZ.js')).seedSchema.shape),
|
|
92
92
|
async boot({ seedState, runId, recorder, twinBaseUrl }) {
|
|
93
|
-
const stripeTwin = await import('./src-
|
|
94
|
-
const { createApp } = await import('./server-
|
|
93
|
+
const stripeTwin = await import('./src-STAXYPD3.js');
|
|
94
|
+
const { createApp } = await import('./server-GECKG2H6.js');
|
|
95
95
|
const {
|
|
96
96
|
applySeed: applyStripeSeed,
|
|
97
97
|
createTwinStripeApp,
|
|
@@ -136,7 +136,7 @@ var TWIN_REGISTRY = {
|
|
|
136
136
|
parseSeed: async (input) => (await import('./seed-W3R53GHH.js')).parseSeed(input),
|
|
137
137
|
seedFields: async () => Object.keys((await import('./seed-W3R53GHH.js')).gmailSeedSchema.shape),
|
|
138
138
|
async boot({ seedState, runId, recorder }) {
|
|
139
|
-
const { createGmailTwinApp, GmailDomain, openGmailTwinDatabase, parseSeed } = await import('./src-
|
|
139
|
+
const { createGmailTwinApp, GmailDomain, openGmailTwinDatabase, parseSeed } = await import('./src-CV7QDV5E.js');
|
|
140
140
|
const db = openGmailTwinDatabase(":memory:");
|
|
141
141
|
const seed = parseSeed(seedState);
|
|
142
142
|
const domain = new GmailDomain(db);
|
|
@@ -165,7 +165,7 @@ var TWIN_REGISTRY = {
|
|
|
165
165
|
LinearDomain,
|
|
166
166
|
openLinearTwinDatabase,
|
|
167
167
|
parseSeed
|
|
168
|
-
} = await import('./src-
|
|
168
|
+
} = await import('./src-D3PKLT54.js');
|
|
169
169
|
const db = openLinearTwinDatabase(":memory:");
|
|
170
170
|
const seed = parseSeed(seedState);
|
|
171
171
|
const domain = new LinearDomain(db);
|
|
@@ -181,7 +181,7 @@ var TWIN_REGISTRY = {
|
|
|
181
181
|
}
|
|
182
182
|
};
|
|
183
183
|
async function createGitHubSmokeApp() {
|
|
184
|
-
const { createGitHubCloneApp } = await import('./src-
|
|
184
|
+
const { createGitHubCloneApp } = await import('./src-46YGR2WY.js');
|
|
185
185
|
return createGitHubCloneApp();
|
|
186
186
|
}
|
|
187
187
|
function defaultPortFor(twin, env = process.env) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TWIN_NAMES, isTwinName, TWIN_REGISTRY } from './chunk-
|
|
1
|
+
import { TWIN_NAMES, isTwinName, TWIN_REGISTRY } from './chunk-BXYPNEJY.js';
|
|
2
2
|
import { createFileBackedRecorderStore, createRecorderStore } from './chunk-TWURH7YM.js';
|
|
3
3
|
|
|
4
4
|
// src/recorder/recorder.ts
|
|
@@ -1,20 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { HostedDiscardRefusedError, HostedOrchError, HostedAuthError, readManifest, normalizeManifestTwins, HostedQuotaError, HostedTrialError } from './chunk-26UAPLHK.js';
|
|
2
|
+
import { criterionSchema, normalizeTaskConfigKeys, finalizeResponseSchema, MOUNTED_TWINS, submitResultResponseSchema, createEvalSessionResponseSchema, createSessionResponseSchema, agentResponseSchema, isMultiTwinSeedEnvelope, sessionPublicSchema } from './chunk-M7ATJ423.js';
|
|
2
3
|
import { gmailSeedSchema, defaultSeedState } from './chunk-PASFBRK4.js';
|
|
3
4
|
import { linearSeedSchema, defaultSeedState as defaultSeedState$1 } from './chunk-3FZY376K.js';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
5
|
+
import { readSeedFileText, parseSeedFileText, soleTwinOf, twinsNamedBy, seedsForTwins } from './chunk-DX2KCFJM.js';
|
|
6
|
+
import { isTwinName, TWIN_REGISTRY } from './chunk-BXYPNEJY.js';
|
|
6
7
|
import { seedSchema as seedSchema$1, parseSeed, defaultSeedState as defaultSeedState$2 } from './chunk-NBOQN5VX.js';
|
|
7
8
|
import { seedSchema } from './chunk-YBWG5JK2.js';
|
|
8
9
|
import { toTwinHttpEventRow } from './chunk-TWURH7YM.js';
|
|
9
10
|
import { redactEvent, redactSecrets } from './chunk-SG6ZTIMT.js';
|
|
10
11
|
import { seedSchema as seedSchema$2 } from './chunk-2K6BJ3PI.js';
|
|
11
|
-
import { mkdir, appendFile, writeFile, readFile, rm, stat, chmod,
|
|
12
|
+
import { mkdir, appendFile, writeFile, readFile, rm, stat, chmod, readdir, rename } from 'node:fs/promises';
|
|
12
13
|
import { existsSync } from 'node:fs';
|
|
13
14
|
import { join, basename, extname, dirname } from 'node:path';
|
|
14
15
|
import { parse } from 'yaml';
|
|
15
16
|
import { z } from 'zod';
|
|
16
17
|
import { randomUUID, createHash } from 'node:crypto';
|
|
17
|
-
import {
|
|
18
|
+
import { homedir } from 'node:os';
|
|
18
19
|
import { execFile, spawn } from 'node:child_process';
|
|
19
20
|
import { promisify } from 'node:util';
|
|
20
21
|
import { createInterface } from 'node:readline';
|
|
@@ -1192,20 +1193,6 @@ function createHostedClient(config) {
|
|
|
1192
1193
|
}
|
|
1193
1194
|
);
|
|
1194
1195
|
},
|
|
1195
|
-
async requestSignalsUploadUrl(sessionId) {
|
|
1196
|
-
return postJson(
|
|
1197
|
-
`/v1/sessions/${encodeURIComponent(sessionId)}/signals-upload-url`,
|
|
1198
|
-
{},
|
|
1199
|
-
(raw) => {
|
|
1200
|
-
if (typeof raw === "object" && raw !== null && typeof raw.url === "string" && typeof raw.key === "string") {
|
|
1201
|
-
return raw;
|
|
1202
|
-
}
|
|
1203
|
-
throw new HostedOrchError(
|
|
1204
|
-
"POST /v1/sessions/:id/signals-upload-url returned unexpected shape"
|
|
1205
|
-
);
|
|
1206
|
-
}
|
|
1207
|
-
);
|
|
1208
|
-
},
|
|
1209
1196
|
async requestMetaUploadUrl(sessionId) {
|
|
1210
1197
|
return postJson(
|
|
1211
1198
|
`/v1/sessions/${encodeURIComponent(sessionId)}/meta-upload-url`,
|
|
@@ -1265,9 +1252,6 @@ function createHostedClient(config) {
|
|
|
1265
1252
|
if (input.stateFinalStorageKey !== void 0) {
|
|
1266
1253
|
body.state_final_storage_key = input.stateFinalStorageKey;
|
|
1267
1254
|
}
|
|
1268
|
-
if (input.signalsStorageKey !== void 0) {
|
|
1269
|
-
body.signals_storage_key = input.signalsStorageKey;
|
|
1270
|
-
}
|
|
1271
1255
|
if (input.perTwinStateKeys !== void 0 && Object.keys(input.perTwinStateKeys).length > 0) {
|
|
1272
1256
|
body.per_twin_state_keys = input.perTwinStateKeys;
|
|
1273
1257
|
}
|
|
@@ -2349,26 +2333,6 @@ async function uploadRunBlobs(client, sessionId, blobs) {
|
|
|
2349
2333
|
return null;
|
|
2350
2334
|
}
|
|
2351
2335
|
}
|
|
2352
|
-
async function uploadSignals() {
|
|
2353
|
-
try {
|
|
2354
|
-
if (blobs.signalsJsonl.trim().length === 0) {
|
|
2355
|
-
return null;
|
|
2356
|
-
}
|
|
2357
|
-
const upload = await client.requestSignalsUploadUrl(sessionId);
|
|
2358
|
-
const ok = await putBlob(
|
|
2359
|
-
upload.url,
|
|
2360
|
-
blobs.signalsJsonl,
|
|
2361
|
-
"application/x-ndjson",
|
|
2362
|
-
"signals.jsonl"
|
|
2363
|
-
);
|
|
2364
|
-
return ok ? upload.key : null;
|
|
2365
|
-
} catch (err) {
|
|
2366
|
-
console.warn(
|
|
2367
|
-
`[pome] signals.jsonl upload skipped (${err instanceof Error ? err.message : String(err)}); continuing with signals_storage_key=null`
|
|
2368
|
-
);
|
|
2369
|
-
return null;
|
|
2370
|
-
}
|
|
2371
|
-
}
|
|
2372
2336
|
async function uploadStates() {
|
|
2373
2337
|
const multiTwin = (blobs.twins?.length ?? 0) > 1;
|
|
2374
2338
|
try {
|
|
@@ -2449,10 +2413,9 @@ async function uploadRunBlobs(client, sessionId, blobs) {
|
|
|
2449
2413
|
return null;
|
|
2450
2414
|
}
|
|
2451
2415
|
}
|
|
2452
|
-
const [eventsKey, stateKeys,
|
|
2416
|
+
const [eventsKey, stateKeys, metaKey] = await Promise.all([
|
|
2453
2417
|
uploadEvents(),
|
|
2454
2418
|
uploadStates(),
|
|
2455
|
-
uploadSignals(),
|
|
2456
2419
|
uploadMeta()
|
|
2457
2420
|
]);
|
|
2458
2421
|
return {
|
|
@@ -2460,8 +2423,7 @@ async function uploadRunBlobs(client, sessionId, blobs) {
|
|
|
2460
2423
|
stateInitialKey: stateKeys.initialKey,
|
|
2461
2424
|
stateFinalKey: stateKeys.finalKey,
|
|
2462
2425
|
perTwinStateKeys: stateKeys.perTwinStateKeys,
|
|
2463
|
-
metaKey
|
|
2464
|
-
signalsKey
|
|
2426
|
+
metaKey
|
|
2465
2427
|
};
|
|
2466
2428
|
}
|
|
2467
2429
|
function scoreFromFinalizeResponse(finalized) {
|
|
@@ -2525,8 +2487,7 @@ function buildAgentEnv2(params) {
|
|
|
2525
2487
|
agentId,
|
|
2526
2488
|
runId,
|
|
2527
2489
|
artifactsDir,
|
|
2528
|
-
slug
|
|
2529
|
-
signalsPath
|
|
2490
|
+
slug
|
|
2530
2491
|
} = params;
|
|
2531
2492
|
const env = {
|
|
2532
2493
|
POME_TASK: prompt,
|
|
@@ -2559,8 +2520,7 @@ function buildAgentEnv2(params) {
|
|
|
2559
2520
|
POME_STRIPE_API_KEY: session.agent_token,
|
|
2560
2521
|
POME_AUTH_TOKEN: session.agent_token,
|
|
2561
2522
|
POME_RUN_ID: runId,
|
|
2562
|
-
POME_ARTIFACTS_DIR: join(artifactsDir, slug, runId)
|
|
2563
|
-
POME_ADAPTER_SIGNALS_PATH: signalsPath
|
|
2523
|
+
POME_ARTIFACTS_DIR: join(artifactsDir, slug, runId)
|
|
2564
2524
|
};
|
|
2565
2525
|
for (const twin of twins) {
|
|
2566
2526
|
const upper = twin.toUpperCase();
|
|
@@ -2597,9 +2557,6 @@ async function runTaskHosted(options) {
|
|
|
2597
2557
|
const agentId = identity.agentId;
|
|
2598
2558
|
const agentVersion = identity.agentVersion;
|
|
2599
2559
|
const agentSdk = identity.framework ?? null;
|
|
2600
|
-
const signalsDir = await mkdtemp(join(tmpdir(), "pome-signals-"));
|
|
2601
|
-
const signalsPath = join(signalsDir, `${randomUUID()}.jsonl`);
|
|
2602
|
-
await writeFile(signalsPath, "");
|
|
2603
2560
|
const session = await createSessionOrExplain(
|
|
2604
2561
|
client,
|
|
2605
2562
|
options.premintedSession,
|
|
@@ -2638,8 +2595,7 @@ async function runTaskHosted(options) {
|
|
|
2638
2595
|
agentId,
|
|
2639
2596
|
runId,
|
|
2640
2597
|
artifactsDir,
|
|
2641
|
-
slug: scenario.slug
|
|
2642
|
-
signalsPath
|
|
2598
|
+
slug: scenario.slug
|
|
2643
2599
|
});
|
|
2644
2600
|
const preflightTimeoutSeconds = Math.min(10, scenario.config.timeout);
|
|
2645
2601
|
const preflight = await runAgentCommand({
|
|
@@ -2650,7 +2606,6 @@ async function runTaskHosted(options) {
|
|
|
2650
2606
|
});
|
|
2651
2607
|
let agentResult = preflight;
|
|
2652
2608
|
if (preflight.exitCode === 0) {
|
|
2653
|
-
await writeFile(signalsPath, "");
|
|
2654
2609
|
agentResult = await runAgentCommand({
|
|
2655
2610
|
command: options.agentCommand,
|
|
2656
2611
|
env,
|
|
@@ -2729,16 +2684,6 @@ async function runTaskHosted(options) {
|
|
|
2729
2684
|
const eventsJsonl = legacyEvents.map((e) => JSON.stringify(redactEvent(toTwinHttpEvent(e)))).join("\n") + "\n";
|
|
2730
2685
|
const stateInitialJson = JSON.stringify(redactSecrets(stateInitial));
|
|
2731
2686
|
const stateFinalJson = JSON.stringify(redactSecrets(stateFinal));
|
|
2732
|
-
let signalsJsonl = "";
|
|
2733
|
-
try {
|
|
2734
|
-
signalsJsonl = redactJsonl(
|
|
2735
|
-
await readFile(signalsPath, "utf8").catch(() => "")
|
|
2736
|
-
);
|
|
2737
|
-
} catch (err) {
|
|
2738
|
-
console.warn(
|
|
2739
|
-
`[pome] signals.jsonl upload skipped (${err instanceof Error ? err.message : String(err)}); continuing with signals_storage_key=null`
|
|
2740
|
-
);
|
|
2741
|
-
}
|
|
2742
2687
|
const metaJson = await readFile(join(artifacts.runDir, "meta.json"), "utf8").catch(
|
|
2743
2688
|
() => "{}"
|
|
2744
2689
|
);
|
|
@@ -2755,7 +2700,6 @@ async function runTaskHosted(options) {
|
|
|
2755
2700
|
eventsJsonl,
|
|
2756
2701
|
stateInitialJson,
|
|
2757
2702
|
stateFinalJson,
|
|
2758
|
-
signalsJsonl,
|
|
2759
2703
|
metaJson,
|
|
2760
2704
|
twins: isMultiTwin ? twins : void 0,
|
|
2761
2705
|
perTwinState
|
|
@@ -2765,7 +2709,6 @@ async function runTaskHosted(options) {
|
|
|
2765
2709
|
initialKey: uploaded.stateInitialKey,
|
|
2766
2710
|
finalKey: uploaded.stateFinalKey
|
|
2767
2711
|
};
|
|
2768
|
-
const signalsKey = uploaded.signalsKey;
|
|
2769
2712
|
const criteriaDefs = scenario.criteria.map((c, idx) => ({
|
|
2770
2713
|
id: `crit_${idx}`,
|
|
2771
2714
|
text: c.text,
|
|
@@ -2794,7 +2737,6 @@ async function runTaskHosted(options) {
|
|
|
2794
2737
|
traceStorageKey: eventsJsonlUrl ?? void 0,
|
|
2795
2738
|
stateInitialStorageKey: stateKeys.initialKey ?? void 0,
|
|
2796
2739
|
stateFinalStorageKey: stateKeys.finalKey ?? void 0,
|
|
2797
|
-
signalsStorageKey: signalsKey ?? void 0,
|
|
2798
2740
|
// Multi-twin (M3): per-twin state storage keys (>=1 key per entry).
|
|
2799
2741
|
// Undefined for single-twin / an older cloud that returned no per_twin
|
|
2800
2742
|
// upload block — the cloud then scores the primary twin from the flat keys.
|
|
@@ -2850,7 +2792,6 @@ async function runTaskHosted(options) {
|
|
|
2850
2792
|
throw err;
|
|
2851
2793
|
} finally {
|
|
2852
2794
|
await client.deleteSession(session.session_id, true, { discard: true }).catch(() => void 0);
|
|
2853
|
-
await rm(signalsDir, { recursive: true, force: true }).catch(() => void 0);
|
|
2854
2795
|
}
|
|
2855
2796
|
}
|
|
2856
2797
|
async function createSessionOrExplain(client, preminted, input) {
|