@pome-sh/cli 0.43.0 → 0.44.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 +237 -117
- package/dist/build-info.json +3 -3
- package/dist/{checks-QYUPKBPT.js → checks-BOOQNOGJ.js} +4 -3
- package/dist/chunk-26UAPLHK.js +191 -0
- package/dist/{chunk-5A6HHA54.js → chunk-3T4FUF43.js} +2 -2
- package/dist/chunk-4LQ4IJOC.js +1 -0
- package/dist/chunk-7ULGZG7X.js +132 -0
- package/dist/{chunk-5KFDRR53.js → chunk-7VZBAHQ2.js} +2 -2
- package/dist/{chunk-OBFHOACQ.js → chunk-G3YRDMBE.js} +12 -71
- package/dist/{chunk-CS7O2ZXB.js → chunk-M7ATJ423.js} +5 -190
- package/dist/{chunk-ELIEDNF3.js → chunk-RYAQ2ZYA.js} +7 -7
- package/dist/{chunk-HRAD7MRX.js → chunk-TWURH7YM.js} +34 -10
- package/dist/{chunk-3YCX3KUL.js → chunk-ZVKPZHFQ.js} +1 -1
- package/dist/{runTrialGroup-4QL6S7QO.js → runTrialGroup-I3PC2AST.js} +8 -6
- package/dist/{server-KC57K5AC.js → server-GECKG2H6.js} +2 -2
- package/dist/src/cli/main.js +71 -140
- package/dist/{src-E7NTZL2F.js → src-252X4AEZ.js} +2 -2
- package/dist/{src-Z63IOSCJ.js → src-CV7QDV5E.js} +2 -2
- package/dist/{src-5F5OTVYT.js → src-D3PKLT54.js} +2 -2
- package/dist/{src-7X62AGW7.js → src-LPTWNBO5.js} +2 -2
- package/dist/{src-ESRY2MC7.js → src-P5MEPJY4.js} +2 -2
- package/dist/twinHarness-YDGIGB4P.js +6 -0
- package/dist/{twinSeed-4VQ7RRCL.js → twinSeed-ADWQ62CA.js} +1 -1
- package/dist/twinStart-E5R26SF4.js +422 -0
- package/dist/twinTape-3XNU3GRW.js +418 -0
- package/examples/agents/mcp-loop-agent.ts +0 -6
- package/package.json +1 -1
- package/dist/twinHarness-WJFDLEAO.js +0 -6
- package/dist/twinStart-QQ64EV3P.js +0 -183
package/README.md
CHANGED
|
@@ -1,168 +1,288 @@
|
|
|
1
1
|
# Pome CLI
|
|
2
2
|
|
|
3
|
-
The `pome`
|
|
4
|
-
|
|
5
|
-
Pome cloud.
|
|
3
|
+
The `pome` CLI runs AI-agent tasks against resettable digital twins of real SaaS APIs.
|
|
4
|
+
It records each run and sends hosted runs to Pome for evaluation.
|
|
6
5
|
|
|
7
|
-
The CLI
|
|
8
|
-
correlates locally. A verdict comes only from the cloud — a hosted `pome run`
|
|
9
|
-
prints it to the terminal and records it to the dashboard, and
|
|
10
|
-
`pome eval <run-dir>` uploads a captured trace for a cloud verdict.
|
|
6
|
+
The CLI does not score locally.
|
|
11
7
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
`pome
|
|
8
|
+
- `pome run` uses the hosted workflow by default. It records the run and prints the hosted verdict.
|
|
9
|
+
- `pome run --local` uses local twins. It records one trace and does not request a verdict.
|
|
10
|
+
- `pome eval` uploads existing local artifacts and prints the hosted verdict.
|
|
11
|
+
|
|
12
|
+
See [docs.pome.sh](https://docs.pome.sh) for the full documentation.
|
|
13
|
+
Use `pome --help` or `pome help <command>` for command details.
|
|
14
|
+
|
|
15
|
+
## Requirements
|
|
16
|
+
|
|
17
|
+
- Node.js 24 or later
|
|
18
|
+
- A Pome account and API key for hosted runs and evaluations
|
|
19
|
+
- A supported model-provider credential when the agent calls a model provider
|
|
20
|
+
|
|
21
|
+
Local twin commands do not require a Pome account.
|
|
15
22
|
|
|
16
23
|
## Install
|
|
17
24
|
|
|
25
|
+
Install the CLI globally:
|
|
26
|
+
|
|
18
27
|
```bash
|
|
19
28
|
npm install -g @pome-sh/cli
|
|
20
|
-
pome --help
|
|
21
29
|
```
|
|
22
30
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
31
|
+
You can also run one command without a global installation:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npx @pome-sh/cli twin start github
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Set Up A Project
|
|
26
38
|
|
|
27
|
-
|
|
39
|
+
Create the starter project in an empty directory:
|
|
28
40
|
|
|
29
41
|
```bash
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
pome
|
|
42
|
+
mkdir pome-example
|
|
43
|
+
cd pome-example
|
|
44
|
+
pome init
|
|
45
|
+
pome login
|
|
46
|
+
pome register agent my-agent
|
|
47
|
+
pome run tasks/01-bug-happy-path.md
|
|
33
48
|
```
|
|
34
49
|
|
|
35
|
-
`
|
|
36
|
-
|
|
37
|
-
|
|
50
|
+
`pome init` writes `pome.json`, starter tasks, and an example agent in an empty directory.
|
|
51
|
+
In an existing project, it writes only the manifest unless you use `--starter`.
|
|
52
|
+
|
|
53
|
+
Set `command` in `pome.json`, or pass `--agent <command>` to `pome run`.
|
|
54
|
+
|
|
55
|
+
## Hosted Workflow
|
|
56
|
+
|
|
57
|
+
Hosted execution is the default for `pome run`.
|
|
58
|
+
The command creates hosted sandboxes, runs the agent, uploads the artifacts, and prints the verdict.
|
|
38
59
|
|
|
39
|
-
|
|
60
|
+
Use `POME_API_KEY` instead of `pome login` in CI.
|
|
61
|
+
Use `-n <count>` to run a hosted trial group of 1 to 20 trials.
|
|
62
|
+
The task `runs` field supplies the count when you omit `-n`.
|
|
63
|
+
|
|
64
|
+
## Local Capture And Hosted Evaluation
|
|
65
|
+
|
|
66
|
+
Use `--local` to run one task against in-process twins.
|
|
67
|
+
This command records artifacts but never scores them.
|
|
40
68
|
|
|
41
69
|
```bash
|
|
42
|
-
pome
|
|
43
|
-
pome
|
|
44
|
-
pome
|
|
45
|
-
pome run tasks/01-bug-happy-path.md --agent "node examples/agents/scripted-triage-agent.ts"
|
|
46
|
-
pome inspect latest # trace/audit view of the last run
|
|
70
|
+
pome run --local tasks/01-bug-happy-path.md
|
|
71
|
+
pome inspect latest
|
|
72
|
+
pome eval
|
|
47
73
|
```
|
|
48
74
|
|
|
49
|
-
|
|
75
|
+
`pome eval` uses `<artifacts-dir>/latest.json` when you omit the run directory.
|
|
76
|
+
You can also give the directory explicitly:
|
|
50
77
|
|
|
51
78
|
```bash
|
|
52
|
-
pome
|
|
53
|
-
pome eval runs/01-bug-happy-path/<run-id> # uploads it for a cloud verdict
|
|
79
|
+
pome eval runs/01-bug-happy-path/<run-id>
|
|
54
80
|
```
|
|
55
81
|
|
|
56
|
-
|
|
82
|
+
`pome eval` uploads the trace to Pome and prints the hosted verdict.
|
|
83
|
+
It does not add a local score.
|
|
84
|
+
|
|
85
|
+
Do not combine `--local` with `-n`.
|
|
86
|
+
Local capture always runs one trial.
|
|
87
|
+
|
|
88
|
+
## Standalone Twins
|
|
57
89
|
|
|
58
|
-
|
|
59
|
-
its tasks, its `pome.json` and its lockfile — into `./<id>`:
|
|
90
|
+
Start a long-running local twin:
|
|
60
91
|
|
|
61
92
|
```bash
|
|
62
|
-
pome
|
|
63
|
-
cd minimal-viktor && npm install
|
|
64
|
-
pome run tasks/01-clean-merge.md
|
|
93
|
+
pome twin start gmail --port 3336
|
|
65
94
|
```
|
|
66
95
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
a
|
|
96
|
+
The command prints the REST URL, MCP URL, and bearer token.
|
|
97
|
+
For Gmail, `POME_GMAIL_TOKEN` is the same Pome session JWT as `POME_AUTH_TOKEN`.
|
|
98
|
+
It is not a Google OAuth token.
|
|
99
|
+
|
|
100
|
+
Create a seed file, then use it to start a twin:
|
|
72
101
|
|
|
73
102
|
```bash
|
|
74
|
-
pome
|
|
103
|
+
pome twin new-seed github --out seed.json
|
|
104
|
+
pome twin start github --seed seed.json
|
|
75
105
|
```
|
|
76
106
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
107
|
+
A supplied seed replaces the default seed.
|
|
108
|
+
It does not merge with the default seed.
|
|
109
|
+
|
|
110
|
+
## Commands
|
|
111
|
+
|
|
112
|
+
| Command | Purpose |
|
|
113
|
+
| --- | --- |
|
|
114
|
+
| `pome init` | Write `pome.json` and, when applicable, starter files. |
|
|
115
|
+
| `pome login` | Sign in and store a hosted API key. |
|
|
116
|
+
| `pome logout` | Remove locally stored hosted credentials. |
|
|
117
|
+
| `pome docs [topic]` | Print or select a documentation URL. |
|
|
118
|
+
| `pome tasks [twin]` | List or copy bundled tasks. |
|
|
119
|
+
| `pome checks [twin]` | List the checks that can grade `[code]` criteria. |
|
|
120
|
+
| `pome checks add <file>` | Add one declared `[code]` criterion to a task. |
|
|
121
|
+
| `pome checks lint <file...>` | Report `[code]` criteria that do not bind to declared checks. |
|
|
122
|
+
| `pome compile-seeds [target]` | Compile prose seed state to `.seed.json` files with Claude. |
|
|
123
|
+
| `pome register agent <name>` | Register an agent and write its slug to `pome.json`. |
|
|
124
|
+
| `pome sandbox create` | Create a hosted sandbox. |
|
|
125
|
+
| `pome sandbox list` | List hosted sandboxes. |
|
|
126
|
+
| `pome sandbox stop <session-id>` | Stop a hosted sandbox. |
|
|
127
|
+
| `pome run [path]` | Run one task or all task files in a directory. Hosted is the default. |
|
|
128
|
+
| `pome doctor` | Check the manifest, twin routing, and egress controls. |
|
|
129
|
+
| `pome eval [run-dir]` | Upload recorded artifacts and request a hosted verdict. |
|
|
130
|
+
| `pome inspect <run>` | Print a trace and audit report. |
|
|
131
|
+
| `pome fix-prompt [target]` | Build a repair prompt from recorded traces and hosted verdicts. |
|
|
132
|
+
| `pome twin start [name]` | Start a standalone local twin. |
|
|
133
|
+
| `pome twin new-seed <name...>` | Print or write a starter seed file. |
|
|
134
|
+
| `pome twin status` | Check the last standalone twin and print its connection values. |
|
|
135
|
+
|
|
136
|
+
## Environment Variables
|
|
137
|
+
|
|
138
|
+
Global hosted configuration:
|
|
139
|
+
|
|
140
|
+
| Variable | Purpose |
|
|
141
|
+
| --- | --- |
|
|
142
|
+
| `POME_API_KEY` | Authenticate hosted commands. This value takes precedence over stored credentials. |
|
|
143
|
+
| `POME_API_URL` | Set the control-plane URL. `--api-url` takes precedence. |
|
|
144
|
+
| `POME_DASHBOARD_URL` | Set the dashboard URL for login and result links. |
|
|
145
|
+
|
|
146
|
+
Agent process configuration:
|
|
147
|
+
|
|
148
|
+
| Variable | Purpose |
|
|
149
|
+
| --- | --- |
|
|
150
|
+
| `POME_AGENT_ENV_ALLOWLIST` | Add comma-separated parent variable names to the agent process. |
|
|
151
|
+
| `POME_EGRESS_ALLOW` | Add comma-separated host patterns to the capture proxy allowlist. |
|
|
152
|
+
| `POME_INHERIT_AGENT_ENV=1` | Pass the full parent environment to the agent. Use this only with trusted agents. |
|
|
153
|
+
| `POME_TRUST_AGENT_COMMAND=1` | Run the agent command through a shell. Use this only with trusted commands. |
|
|
81
154
|
|
|
82
|
-
The
|
|
83
|
-
always the one this version was released with. `POME_EXAMPLE_REF` overrides the
|
|
84
|
-
ref when you want a branch.
|
|
155
|
+
The CLI passes these provider variables to the agent by default when they are set:
|
|
85
156
|
|
|
86
|
-
|
|
87
|
-
|
|
157
|
+
- `AI_GATEWAY_API_KEY`
|
|
158
|
+
- `ANTHROPIC_API_KEY`
|
|
159
|
+
- `CLAUDE_CODE_OAUTH_TOKEN`
|
|
160
|
+
- `GOOGLE_API_KEY`
|
|
161
|
+
- `GOOGLE_GENERATIVE_AI_API_KEY`
|
|
162
|
+
- `OPENAI_API_KEY`
|
|
163
|
+
- `OPENROUTER_API_KEY`
|
|
88
164
|
|
|
89
|
-
|
|
165
|
+
`pome compile-seeds` requires `ANTHROPIC_API_KEY`.
|
|
90
166
|
|
|
91
|
-
|
|
92
|
-
code is the verdict**. Gate CI on it directly.
|
|
167
|
+
Standalone twin configuration:
|
|
93
168
|
|
|
94
|
-
|
|
|
169
|
+
| Variable | Purpose |
|
|
95
170
|
| --- | --- |
|
|
96
|
-
| `
|
|
97
|
-
| `
|
|
98
|
-
| `
|
|
99
|
-
| `
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
171
|
+
| `PORT` | Set the listen port for `pome twin start`. `--port` takes precedence. |
|
|
172
|
+
| `POME_SEED_JSON` | Supply seed JSON. `--seed` takes precedence. |
|
|
173
|
+
| `TWIN_AUTH_SECRET` | Supply the secret that signs local session JWTs. |
|
|
174
|
+
| `POME_TWIN_DATA_DIR` | Set the directory for the persisted twin secret. |
|
|
175
|
+
|
|
176
|
+
The twin entry points also accept their provider-specific host, port, database, and no-seed variables.
|
|
177
|
+
See [`CONTRACT.md`](../CONTRACT.md) for that runtime interface.
|
|
178
|
+
|
|
179
|
+
## Artifacts
|
|
180
|
+
|
|
181
|
+
The default artifact root is `runs/`.
|
|
182
|
+
Use the global `--artifacts-dir <dir>` option to select another root.
|
|
183
|
+
|
|
184
|
+
Each completed run uses this directory format:
|
|
185
|
+
|
|
186
|
+
```text
|
|
187
|
+
<artifacts-dir>/<task-slug>/<run-id>/
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
The six core files are:
|
|
191
|
+
|
|
192
|
+
| File | Content |
|
|
193
|
+
| --- | --- |
|
|
194
|
+
| `meta.json` | Run identity, times, agent exit, twins, and format versions. |
|
|
195
|
+
| `events.jsonl` | Redacted twin, model, and adapter events. |
|
|
196
|
+
| `state_initial.json` | Initial state for the primary twin. |
|
|
197
|
+
| `state_final.json` | Final state for the primary twin. |
|
|
198
|
+
| `stdout.txt` | Redacted agent standard output. |
|
|
199
|
+
| `stderr.log` | Redacted agent standard error. |
|
|
200
|
+
|
|
201
|
+
A run can also contain these files:
|
|
202
|
+
|
|
203
|
+
| File | Condition |
|
|
204
|
+
| --- | --- |
|
|
205
|
+
| `egress.jsonl` | The capture proxy records refused connections here. |
|
|
206
|
+
| `state_final.<twin>.json` | A multi-twin run records each additional final state. |
|
|
207
|
+
| `verdict.json` | A hosted `pome run` caches the hosted verdict for `pome fix-prompt`. |
|
|
208
|
+
| `eval-session.json` | `pome eval` records the hosted evaluation session for safe reuse. |
|
|
209
|
+
|
|
210
|
+
The artifact root also contains `latest.json`.
|
|
211
|
+
It points to the most recent run directory.
|
|
212
|
+
|
|
213
|
+
The CLI never writes `score.json`.
|
|
214
|
+
A hosted verdict comes from Pome.
|
|
215
|
+
|
|
216
|
+
## Exit Codes
|
|
217
|
+
|
|
218
|
+
### Hosted `pome run` And `pome eval`
|
|
219
|
+
|
|
220
|
+
| Code | Meaning |
|
|
221
|
+
| --- | --- |
|
|
222
|
+
| `0` | The hosted verdict is `pass`. |
|
|
223
|
+
| `1` | The hosted verdict is `fail` or `incomplete`. |
|
|
224
|
+
| `2` | A twin, missing agent command, malformed task configuration, network, or orchestration error prevented a verdict. |
|
|
225
|
+
| `3` | Authentication failed. |
|
|
226
|
+
| `4` | The account exceeded a quota. |
|
|
227
|
+
| `5` | The CLI rejected the invocation during validation, for example because a path, option, or option combination is invalid. |
|
|
228
|
+
|
|
229
|
+
For `pome run`, the task supplies the pass threshold.
|
|
230
|
+
For `pome eval`, the pass threshold is `100`.
|
|
231
|
+
|
|
232
|
+
For a hosted `pome run`, read `state` in `verdict.json` to distinguish `fail` from `incomplete`.
|
|
233
|
+
The possible values are `"pass"`, `"fail"`, and `"incomplete"`.
|
|
234
|
+
|
|
235
|
+
The `evaluated`, `not_evaluated`, `pre_satisfied`, and `total` fields describe grading coverage.
|
|
236
|
+
`score` is a percentage over `evaluated` criteria only.
|
|
237
|
+
Thus, `not_evaluated > 0` means that the score does not cover the complete task.
|
|
238
|
+
|
|
239
|
+
### Hosted Trial Groups
|
|
240
|
+
|
|
241
|
+
`pome run -n k` returns one code for the group when `k` is greater than `1`.
|
|
242
|
+
|
|
243
|
+
| Code | Meaning |
|
|
244
|
+
| --- | --- |
|
|
245
|
+
| `0` | At least one trial completed and every completed trial passed. |
|
|
246
|
+
| `1` | At least one completed trial failed or was incomplete. |
|
|
247
|
+
| `2` | No trial completed. |
|
|
248
|
+
|
|
249
|
+
Errored trials do not enter the verdict fraction.
|
|
250
|
+
An incomplete trial also prevents exit `0`.
|
|
251
|
+
|
|
252
|
+
### Local `pome run --local`
|
|
253
|
+
|
|
254
|
+
| Code | Meaning |
|
|
255
|
+
| --- | --- |
|
|
256
|
+
| `0` | The agent completed and the CLI recorded the trace. This code is not a verdict. |
|
|
257
|
+
| `2` | A local twin, missing agent command, malformed task configuration, or runner error prevented capture. |
|
|
258
|
+
| `3` | The agent failed, timed out, or failed its preflight. |
|
|
259
|
+
| `5` | The CLI rejected the invocation during validation, for example because a path, option, or option combination is invalid. |
|
|
260
|
+
|
|
261
|
+
Do not use a local exit `0` as a CI quality gate.
|
|
262
|
+
Run `pome eval <run-dir>` to request a verdict.
|
|
263
|
+
|
|
264
|
+
### `pome fix-prompt`
|
|
265
|
+
|
|
266
|
+
- Exit `0` means that the command succeeded. Standard output can be empty when all run sets passed.
|
|
267
|
+
- Exit `1` means that the newest non-passing set is incomplete.
|
|
268
|
+
- Exit `5` means that the target or arguments are invalid.
|
|
269
|
+
|
|
270
|
+
## Contribute
|
|
271
|
+
|
|
272
|
+
Run these commands from the repository root:
|
|
144
273
|
|
|
145
274
|
```bash
|
|
146
275
|
npm install
|
|
147
|
-
npm run typecheck
|
|
148
276
|
npm run build
|
|
277
|
+
npm run typecheck
|
|
149
278
|
npx vitest run --project cli
|
|
150
279
|
```
|
|
151
280
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
### Versioning — every behavior change ships with a release, and you do not write the number
|
|
281
|
+
Use `npm run test:contract` for the packaged twin runtime contract.
|
|
282
|
+
Run `node --test contract/cli-start.test.mjs` after you build the CLI front door.
|
|
155
283
|
|
|
156
|
-
|
|
157
|
-
`(minor)`) heading, above the newest released one, and leave `version` in
|
|
158
|
-
`cli/package.json` alone — a PR that moves it fails CI. Merging to `main` is the
|
|
159
|
-
release trigger: `.github/workflows/allocate-version.yml` allocates the number
|
|
160
|
-
there, rewriting that heading and the manifest in one commit, and
|
|
161
|
-
`.github/workflows/release.yml` compares the local version against npm and
|
|
162
|
-
publishes when they differ. `pome --version` reports the allocated value from a
|
|
163
|
-
build-time constant, so a user can always tell whether their install carries a
|
|
164
|
-
given fix.
|
|
284
|
+
The package publishes `pome` from `cli/dist/src/cli/main.js`.
|
|
165
285
|
|
|
166
286
|
## License
|
|
167
287
|
|
|
168
|
-
Apache-2.0. See [`LICENSE`](
|
|
288
|
+
Apache-2.0. See [`LICENSE`](../LICENSE).
|
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.44.0",
|
|
4
|
+
"git_sha": "a80259dcddd5ec6f1a16dba3a6f252539996ebb7",
|
|
5
|
+
"build_time": "2026-09-16T12:52:26.327Z"
|
|
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-YDGIGB4P.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 };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { TWIN_NAMES, isTwinName, TWIN_REGISTRY } from './chunk-
|
|
2
|
-
import { createFileBackedRecorderStore, createRecorderStore } from './chunk-
|
|
1
|
+
import { TWIN_NAMES, isTwinName, TWIN_REGISTRY } from './chunk-RYAQ2ZYA.js';
|
|
2
|
+
import { createFileBackedRecorderStore, createRecorderStore } from './chunk-TWURH7YM.js';
|
|
3
3
|
|
|
4
4
|
// src/recorder/recorder.ts
|
|
5
5
|
function createRecorder(options = {}) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|