@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.
Files changed (29) hide show
  1. package/README.md +237 -117
  2. package/dist/build-info.json +3 -3
  3. package/dist/{checks-QYUPKBPT.js → checks-BOOQNOGJ.js} +4 -3
  4. package/dist/chunk-26UAPLHK.js +191 -0
  5. package/dist/{chunk-5A6HHA54.js → chunk-3T4FUF43.js} +2 -2
  6. package/dist/chunk-4LQ4IJOC.js +1 -0
  7. package/dist/chunk-7ULGZG7X.js +132 -0
  8. package/dist/{chunk-5KFDRR53.js → chunk-7VZBAHQ2.js} +2 -2
  9. package/dist/{chunk-OBFHOACQ.js → chunk-G3YRDMBE.js} +12 -71
  10. package/dist/{chunk-CS7O2ZXB.js → chunk-M7ATJ423.js} +5 -190
  11. package/dist/{chunk-ELIEDNF3.js → chunk-RYAQ2ZYA.js} +7 -7
  12. package/dist/{chunk-HRAD7MRX.js → chunk-TWURH7YM.js} +34 -10
  13. package/dist/{chunk-3YCX3KUL.js → chunk-ZVKPZHFQ.js} +1 -1
  14. package/dist/{runTrialGroup-4QL6S7QO.js → runTrialGroup-I3PC2AST.js} +8 -6
  15. package/dist/{server-KC57K5AC.js → server-GECKG2H6.js} +2 -2
  16. package/dist/src/cli/main.js +71 -140
  17. package/dist/{src-E7NTZL2F.js → src-252X4AEZ.js} +2 -2
  18. package/dist/{src-Z63IOSCJ.js → src-CV7QDV5E.js} +2 -2
  19. package/dist/{src-5F5OTVYT.js → src-D3PKLT54.js} +2 -2
  20. package/dist/{src-7X62AGW7.js → src-LPTWNBO5.js} +2 -2
  21. package/dist/{src-ESRY2MC7.js → src-P5MEPJY4.js} +2 -2
  22. package/dist/twinHarness-YDGIGB4P.js +6 -0
  23. package/dist/{twinSeed-4VQ7RRCL.js → twinSeed-ADWQ62CA.js} +1 -1
  24. package/dist/twinStart-E5R26SF4.js +422 -0
  25. package/dist/twinTape-3XNU3GRW.js +418 -0
  26. package/examples/agents/mcp-loop-agent.ts +0 -6
  27. package/package.json +1 -1
  28. package/dist/twinHarness-WJFDLEAO.js +0 -6
  29. package/dist/twinStart-QQ64EV3P.js +0 -183
package/README.md CHANGED
@@ -1,168 +1,288 @@
1
1
  # Pome CLI
2
2
 
3
- The `pome` command runs AI-agent tasks against resettable digital twins of
4
- real SaaS APIs (GitHub, Stripe, …), captures the trace, and gets a verdict from
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 is **capture-only**: it records raw traces and never scores, judges, or
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
- **📚 Full documentation lives at [docs.pome.sh](https://docs.pome.sh).**
13
- Run `pome --help` (or `pome help <command>`) for the CLI reference, and
14
- `pome docs getting-started` to print the quickstart's URL.
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
- Or run it without installing: `npx @pome-sh/cli <command>` e.g.
24
- `npx @pome-sh/cli twin start github` boots a local GitHub twin with nothing
25
- but Node ≥ 24.
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
- Gmail is first-party too:
39
+ Create the starter project in an empty directory:
28
40
 
29
41
  ```bash
30
- npx @pome-sh/cli twin start gmail --port 3336
31
- # prints POME_GMAIL_REST_URL, POME_GMAIL_MCP_URL, and POME_GMAIL_TOKEN
32
- pome tasks gmail --copy
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
- `POME_GMAIL_TOKEN` is the same Pome session JWT as `POME_AUTH_TOKEN`; it is not
36
- a Google OAuth token. Hosted Gmail availability is gated separately from the
37
- local/OSS package release.
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
- ## Quickstart
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 login # one-time; opens the dashboard to sign in
43
- pome init # scaffolds tasks/, examples/agents/, runs/, pome.json
44
- pome register agent my-agent # scopes runs to this project
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
- To capture a trace without the cloud (self-host), then get a verdict later:
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 run --local tasks/01-bug-happy-path.md # captures a raw trace only, no verdict
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
- ## Start from an example
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
- `pome init --example <id>` fetches a complete, runnable example — its agent,
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 init --example minimal-viktor # a merge bot on the GitHub + Slack twins
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
- An example is named by **id**, never by path that is the whole point. The ids
68
- are derived from the example directories rather than restated anywhere, so an
69
- example that is renamed or deleted stops answering to the old id on the next
70
- command, with the valid ids printed underneath, instead of going quietly 404 in
71
- a link someone typed months ago. An unknown id lists every available one:
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 init --example nope # the full list, each with what it teaches
103
+ pome twin new-seed github --out seed.json
104
+ pome twin start github --seed seed.json
75
105
  ```
76
106
 
77
- Two kinds are on that list: **agents for Pome to grade**, which you run with
78
- `pome run`, and **integration harnesses** (Braintrust, LangSmith) that drive Pome
79
- from their own eval runner and are started by it, not by `pome run`. The output
80
- tells you which one you scaffolded.
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 files come from GitHub at the commit that built your CLI, so an example is
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
- See [docs.pome.sh](https://docs.pome.sh) for the task library, authentication,
87
- the Stripe/Slack twins, and everything else.
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
- ## CI one-shot the exit-code contract
165
+ `pome compile-seeds` requires `ANTHROPIC_API_KEY`.
90
166
 
91
- `pome run <task>` is the CI one-shot: one hosted, scored run, and its **exit
92
- code is the verdict**. Gate CI on it directly.
167
+ Standalone twin configuration:
93
168
 
94
- | Exit code | Meaning |
169
+ | Variable | Purpose |
95
170
  | --- | --- |
96
- | `0` | pass (hosted/scored run), or trace captured (`--local`, not scored) |
97
- | `1` | ran and scored **below** the pass threshold, **or ran `INCOMPLETE`** |
98
- | `2` | twin / orchestration error (network, 5xx, twin spawn failed) |
99
- | `3` | auth error (401/403) `pome login` again, or set `POME_API_KEY` in CI |
100
- | `4` | quota exceeded (402/429) |
101
- | `5` | usage error (bad flags, missing task file) |
102
-
103
- Three rules CI must honor:
104
-
105
- - **`--local` is not a verdict.** A `--local` run captures a raw trace and never
106
- scores, so its exit `0` means "trace captured," not "passed." Never gate CI on
107
- a `--local` exit code score it later with `pome eval <run-dir>`.
108
- - **`INCOMPLETE` shares exit `1`, and it is not the agent's failure.** A run
109
- whose criteria could not all be graded exits `1` rather than mapping its
110
- partial score to a code — a run whose checks never ran is not a green CI
111
- signal. The cost is stated rather than hidden: **`1` cannot tell "the agent
112
- regressed" from "we could not grade it."** To separate them programmatically,
113
- do not compare `score` against `pass_threshold` yourself — a run with a third
114
- of its criteria unevaluated can still read `score: 100, pass_threshold: 100`
115
- with nothing in those two fields alone saying so. Read `state` in the
116
- `verdict.json` a hosted `pome run` writes to
117
- `<artifacts-dir>/<task-slug>/<session-id>/verdict.json`: `"pass"`, `"fail"`,
118
- or `"incomplete"` the same word the terminal prints beside the score, and
119
- the field to gate on. The `evaluated` / `not_evaluated` / `pre_satisfied` /
120
- `total` counts alongside it say how much of the task `score` covers:
121
- **`score` is a percentage over `evaluated` alone**, so `not_evaluated > 0`
122
- means `score` is silent about part of the run, and `evaluated: 0` means it
123
- scored nothing at all (the cloud sends `0` there for want of a denominator
124
- "nothing was scored", not "nothing was correct").
125
- - **Trial groups map as a whole.** `pome run -n k` (k>1) collapses the whole
126
- group to one code: `0` = at least one trial completed and every completed
127
- trial passed; `1` = at least one completed trial failed its threshold **or was
128
- incomplete**; `2` = no trial completed. Errored and incomplete trials are
129
- excluded from the verdict fraction (`3 of 4 passed · 1 incomplete`) so neither
130
- is counted as a pass nor charged to the agent as a loss — but a group holding
131
- one cannot exit `0`.
132
- - **`pome fix-prompt` uses the same codes, and its `1` is only ever
133
- INCOMPLETE.** Building a prompt for a failed run set exits `0` (the prompt is
134
- on stdout, and stdout being non-empty is the signal that there was something
135
- to fix); an all-green root exits `0` with nothing on stdout; a bad argument or
136
- a root with no readable run sets exits `5`. `1` is reserved for the one case
137
- where the newest non-passing set was never fully graded: no prompt is built,
138
- because a run whose checks never ran is not evidence of an agent defect. This
139
- matches `pome run`, where `1` also covers INCOMPLETE — the two commands do not
140
- disagree about what an ungraded run exits, and `verdict.json`'s `state` stays
141
- the field to read when a script needs the reason rather than the code.
142
-
143
- ## Development
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
- The package publishes the `pome` binary from `dist/src/cli/main.js`.
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
- Add the user-facing entry to `CHANGELOG.md` under an `## Unreleased (patch)` (or
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`](./LICENSE).
288
+ Apache-2.0. See [`LICENSE`](../LICENSE).
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "package": "pome-sh",
3
- "version": "0.43.0",
4
- "git_sha": "589885b59adab9a5fded977620a6adc25125da85",
5
- "build_time": "2026-09-01T07:18:35.031Z"
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-CS7O2ZXB.js';
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-5KFDRR53.js';
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-WJFDLEAO.js');
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-ELIEDNF3.js';
2
- import { createFileBackedRecorderStore, createRecorderStore } from './chunk-HRAD7MRX.js';
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
+