@pome-sh/cli 0.34.2 → 0.35.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 +30 -0
- package/dist/build-info.json +3 -3
- package/dist/src/cli/main.js +409 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -53,6 +53,36 @@ pome run --local tasks/01-bug-happy-path.md # captures a raw trace only, no ve
|
|
|
53
53
|
pome eval runs/01-bug-happy-path/<run-id> # uploads it for a cloud verdict
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
+
## Start from an example
|
|
57
|
+
|
|
58
|
+
`pome init --example <id>` fetches a complete, runnable example — its agent,
|
|
59
|
+
its tasks, its `pome.json` and its lockfile — into `./<id>`:
|
|
60
|
+
|
|
61
|
+
```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
|
|
65
|
+
```
|
|
66
|
+
|
|
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:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
pome init --example nope # → the full list, each with what it teaches
|
|
75
|
+
```
|
|
76
|
+
|
|
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.
|
|
81
|
+
|
|
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.
|
|
85
|
+
|
|
56
86
|
See [docs.pome.sh](https://docs.pome.sh) for the task library, authentication,
|
|
57
87
|
the Stripe/Slack twins, and everything else.
|
|
58
88
|
|
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-08-
|
|
3
|
+
"version": "0.35.0",
|
|
4
|
+
"git_sha": "d34cec8ae64d618dee1e0121d5284c78177820cc",
|
|
5
|
+
"build_time": "2026-08-29T16:22:08.716Z"
|
|
6
6
|
}
|
package/dist/src/cli/main.js
CHANGED
|
@@ -24,7 +24,7 @@ import { redactEvent, redactSecrets } from '../../chunk-SG6ZTIMT.js';
|
|
|
24
24
|
import '../../chunk-CF6EIU2U.js';
|
|
25
25
|
import { Command } from 'commander';
|
|
26
26
|
import { existsSync, readFileSync, realpathSync, statSync, constants } from 'node:fs';
|
|
27
|
-
import { mkdir, readFile, rm,
|
|
27
|
+
import { mkdir, readFile, rm, writeFile, readdir, copyFile, stat, cp } from 'node:fs/promises';
|
|
28
28
|
import { dirname, resolve, join, basename, relative, extname } from 'node:path';
|
|
29
29
|
import { fileURLToPath } from 'node:url';
|
|
30
30
|
import { execFile } from 'node:child_process';
|
|
@@ -4344,6 +4344,380 @@ var ClaudeManagedDeferredError = class extends Error {
|
|
|
4344
4344
|
this.name = "ClaudeManagedDeferredError";
|
|
4345
4345
|
}
|
|
4346
4346
|
};
|
|
4347
|
+
|
|
4348
|
+
// src/cli/example-catalog.ts
|
|
4349
|
+
var CATALOG_EXAMPLES = [
|
|
4350
|
+
{
|
|
4351
|
+
id: "gmail-retry-notify",
|
|
4352
|
+
root: "agent-examples",
|
|
4353
|
+
rel: "agent-examples/gmail-retry-notify",
|
|
4354
|
+
description: "Bundled Pome example: a Gmail notification agent that must retry throttled (429) sends without duplicating already-delivered ones. Teaches retry / partial-failure against the Gmail twin's rate-limited fault seed.",
|
|
4355
|
+
files: [
|
|
4356
|
+
".gitignore",
|
|
4357
|
+
"README.md",
|
|
4358
|
+
"VERIFICATION.md",
|
|
4359
|
+
"package-lock.json",
|
|
4360
|
+
"package.json",
|
|
4361
|
+
"pome.json",
|
|
4362
|
+
"src/index.ts",
|
|
4363
|
+
"tasks/01-throttled-send.md",
|
|
4364
|
+
"tasks/01-throttled-send.seed.json",
|
|
4365
|
+
"tsconfig.json"
|
|
4366
|
+
]
|
|
4367
|
+
},
|
|
4368
|
+
{
|
|
4369
|
+
id: "merge-agent",
|
|
4370
|
+
root: "agent-examples",
|
|
4371
|
+
rel: "agent-examples/merge-agent",
|
|
4372
|
+
description: "Bundled Pome example: a model-driven GitHub PR merge agent (Vercel AI SDK) run against the local GitHub twin's REST surface.",
|
|
4373
|
+
files: [
|
|
4374
|
+
".gitignore",
|
|
4375
|
+
"README.md",
|
|
4376
|
+
"package-lock.json",
|
|
4377
|
+
"package.json",
|
|
4378
|
+
"pome.json",
|
|
4379
|
+
"src/index.ts",
|
|
4380
|
+
"tasks/01-identity-spoof.md",
|
|
4381
|
+
"tasks/01-identity-spoof.seed.json",
|
|
4382
|
+
"tsconfig.json"
|
|
4383
|
+
]
|
|
4384
|
+
},
|
|
4385
|
+
{
|
|
4386
|
+
id: "minimal-viktor",
|
|
4387
|
+
root: "agent-examples",
|
|
4388
|
+
rel: "agent-examples/minimal-viktor",
|
|
4389
|
+
description: "Bundled Pome example: minimal-viktor, an MVP viktor.com-style merge bot (Vercel AI SDK) that merges safe PRs on the GitHub twin and reports every outcome to the Slack twin.",
|
|
4390
|
+
files: [
|
|
4391
|
+
".gitignore",
|
|
4392
|
+
"README.md",
|
|
4393
|
+
"package-lock.json",
|
|
4394
|
+
"package.json",
|
|
4395
|
+
"pome.json",
|
|
4396
|
+
"scripts/pome-api.ts",
|
|
4397
|
+
"scripts/run-trials.ts",
|
|
4398
|
+
"src/index.ts",
|
|
4399
|
+
"src/model-routing.ts",
|
|
4400
|
+
"src/telemetry.ts",
|
|
4401
|
+
"tasks/01-clean-merge.md",
|
|
4402
|
+
"tasks/01-clean-merge.seed.json",
|
|
4403
|
+
"tasks/02-two-safe-prs.md",
|
|
4404
|
+
"tasks/02-two-safe-prs.seed.json",
|
|
4405
|
+
"tasks/03-failing-ci.md",
|
|
4406
|
+
"tasks/03-failing-ci.seed.json",
|
|
4407
|
+
"tasks/04-unauthorized-author.md",
|
|
4408
|
+
"tasks/04-unauthorized-author.seed.json",
|
|
4409
|
+
"tasks/05-typosquat-backdoor.md",
|
|
4410
|
+
"tasks/05-typosquat-backdoor.seed.json",
|
|
4411
|
+
"tasks/06-phishing-impersonation.md",
|
|
4412
|
+
"tasks/06-phishing-impersonation.seed.json",
|
|
4413
|
+
"test/example.test.ts",
|
|
4414
|
+
"test/model-routing.test.ts",
|
|
4415
|
+
"tsconfig.json",
|
|
4416
|
+
"vitest.config.ts"
|
|
4417
|
+
]
|
|
4418
|
+
},
|
|
4419
|
+
{
|
|
4420
|
+
id: "minimal-viktor-langgraph",
|
|
4421
|
+
root: "agent-examples",
|
|
4422
|
+
rel: "agent-examples/minimal-viktor-langgraph",
|
|
4423
|
+
description: "Bundled Pome example: minimal-viktor built on LangGraph, observed via OpenInference OTel instrumentation. A viktor.com-style merge bot that merges safe PRs on the GitHub twin and reports every outcome to the Slack twin.",
|
|
4424
|
+
files: [
|
|
4425
|
+
".gitignore",
|
|
4426
|
+
"README.md",
|
|
4427
|
+
"VERIFICATION.md",
|
|
4428
|
+
"package-lock.json",
|
|
4429
|
+
"package.json",
|
|
4430
|
+
"pome.json",
|
|
4431
|
+
"scripts/pome-api.ts",
|
|
4432
|
+
"scripts/run-trials.ts",
|
|
4433
|
+
"src/graph.ts",
|
|
4434
|
+
"src/index.ts",
|
|
4435
|
+
"src/model-routing.ts",
|
|
4436
|
+
"src/telemetry.ts",
|
|
4437
|
+
"src/tools.ts",
|
|
4438
|
+
"tasks/01-clean-merge.md",
|
|
4439
|
+
"tasks/01-clean-merge.seed.json",
|
|
4440
|
+
"tasks/02-two-safe-prs.md",
|
|
4441
|
+
"tasks/02-two-safe-prs.seed.json",
|
|
4442
|
+
"tasks/03-failing-ci.md",
|
|
4443
|
+
"tasks/03-failing-ci.seed.json",
|
|
4444
|
+
"tasks/04-unauthorized-author.md",
|
|
4445
|
+
"tasks/04-unauthorized-author.seed.json",
|
|
4446
|
+
"tasks/05-typosquat-backdoor.md",
|
|
4447
|
+
"tasks/05-typosquat-backdoor.seed.json",
|
|
4448
|
+
"tasks/06-phishing-impersonation.md",
|
|
4449
|
+
"tasks/06-phishing-impersonation.seed.json",
|
|
4450
|
+
"test/example.test.ts",
|
|
4451
|
+
"test/model-routing.test.ts",
|
|
4452
|
+
"tsconfig.json",
|
|
4453
|
+
"vitest.config.ts"
|
|
4454
|
+
]
|
|
4455
|
+
},
|
|
4456
|
+
{
|
|
4457
|
+
id: "pr-summary-agent",
|
|
4458
|
+
root: "agent-examples",
|
|
4459
|
+
rel: "agent-examples/pr-summary-agent",
|
|
4460
|
+
description: "Bundled Pome example: a Claude Agent SDK agent that summarizes pull requests on the local GitHub twin.",
|
|
4461
|
+
files: [
|
|
4462
|
+
".gitignore",
|
|
4463
|
+
"README.md",
|
|
4464
|
+
"package-lock.json",
|
|
4465
|
+
"package.json",
|
|
4466
|
+
"pome.json",
|
|
4467
|
+
"src/index.ts",
|
|
4468
|
+
"tasks/01-summarize-prs.md",
|
|
4469
|
+
"tasks/01-summarize-prs.seed.json",
|
|
4470
|
+
"tsconfig.json"
|
|
4471
|
+
]
|
|
4472
|
+
},
|
|
4473
|
+
{
|
|
4474
|
+
id: "pr-summary-review",
|
|
4475
|
+
root: "agent-examples",
|
|
4476
|
+
rel: "agent-examples/pr-summary-review",
|
|
4477
|
+
description: "Bundled Pome example: a Claude Agent SDK agent that summarizes and reviews pull requests on the local GitHub twin.",
|
|
4478
|
+
files: [
|
|
4479
|
+
".gitignore",
|
|
4480
|
+
"README.md",
|
|
4481
|
+
"package-lock.json",
|
|
4482
|
+
"package.json",
|
|
4483
|
+
"pome.json",
|
|
4484
|
+
"src/index.ts",
|
|
4485
|
+
"tasks/01-clean-prs.md",
|
|
4486
|
+
"tasks/01-clean-prs.seed.json",
|
|
4487
|
+
"tasks/02-buggy-pr.md",
|
|
4488
|
+
"tasks/02-buggy-pr.seed.json",
|
|
4489
|
+
"tasks/03-risky-pr.md",
|
|
4490
|
+
"tasks/03-risky-pr.seed.json",
|
|
4491
|
+
"tsconfig.json"
|
|
4492
|
+
]
|
|
4493
|
+
},
|
|
4494
|
+
{
|
|
4495
|
+
id: "support-triage",
|
|
4496
|
+
root: "agent-examples",
|
|
4497
|
+
rel: "agent-examples/support-triage",
|
|
4498
|
+
description: "Pome hero example: the support-triage examinee as a local Claude Agent SDK subprocess, wired to the GitHub + Slack twins over MCP.",
|
|
4499
|
+
files: [
|
|
4500
|
+
"README.md",
|
|
4501
|
+
"VERIFICATION.md",
|
|
4502
|
+
"agents/support-triage-v1.yaml",
|
|
4503
|
+
"agents/support-triage-v2.yaml",
|
|
4504
|
+
"package-lock.json",
|
|
4505
|
+
"package.json",
|
|
4506
|
+
"pome.json",
|
|
4507
|
+
"src/index.ts",
|
|
4508
|
+
"tasks/duplicate-issue.md",
|
|
4509
|
+
"test/example.test.ts",
|
|
4510
|
+
"tsconfig.json",
|
|
4511
|
+
"vitest.config.ts"
|
|
4512
|
+
]
|
|
4513
|
+
},
|
|
4514
|
+
{
|
|
4515
|
+
id: "triage-agent",
|
|
4516
|
+
root: "agent-examples",
|
|
4517
|
+
rel: "agent-examples/triage-agent",
|
|
4518
|
+
description: "Bundled Pome example: a Claude Agent SDK agent that triages issues on the local GitHub twin.",
|
|
4519
|
+
files: [
|
|
4520
|
+
".gitignore",
|
|
4521
|
+
"README.md",
|
|
4522
|
+
"package-lock.json",
|
|
4523
|
+
"package.json",
|
|
4524
|
+
"pome.json",
|
|
4525
|
+
"src/index.ts",
|
|
4526
|
+
"tasks/01-triage-acme-issues.md",
|
|
4527
|
+
"tasks/01-triage-acme-issues.seed.json",
|
|
4528
|
+
"tasks/02-injection-issue-body.md",
|
|
4529
|
+
"tasks/02-injection-issue-body.seed.json",
|
|
4530
|
+
"test/example.test.ts",
|
|
4531
|
+
"tsconfig.json",
|
|
4532
|
+
"vitest.config.ts"
|
|
4533
|
+
]
|
|
4534
|
+
},
|
|
4535
|
+
{
|
|
4536
|
+
id: "braintrust",
|
|
4537
|
+
root: "integration-examples",
|
|
4538
|
+
rel: "integration-examples/braintrust",
|
|
4539
|
+
description: "Bundled Pome example: Braintrust Eval() gives every dataset row its own hosted Pome sandbox, and each Pome criterion comes back as its own Braintrust score column.",
|
|
4540
|
+
files: [
|
|
4541
|
+
".gitignore",
|
|
4542
|
+
"README.md",
|
|
4543
|
+
"package-lock.json",
|
|
4544
|
+
"package.json",
|
|
4545
|
+
"pome.json",
|
|
4546
|
+
"scripts/write-task.ts",
|
|
4547
|
+
"src/agent.ts",
|
|
4548
|
+
"src/dataset.ts",
|
|
4549
|
+
"src/index.ts",
|
|
4550
|
+
"src/pome.ts",
|
|
4551
|
+
"src/scoring.ts",
|
|
4552
|
+
"src/task.ts",
|
|
4553
|
+
"src/telemetry.ts",
|
|
4554
|
+
"src/url.ts",
|
|
4555
|
+
"tasks/lost-response-double-refund.md",
|
|
4556
|
+
"test/agent.test.ts",
|
|
4557
|
+
"test/braintrust-seam.test.ts",
|
|
4558
|
+
"test/dataset.test.ts",
|
|
4559
|
+
"test/fixtures/finalize-careful.json",
|
|
4560
|
+
"test/fixtures/finalize-double-refund.json",
|
|
4561
|
+
"test/index.test.ts",
|
|
4562
|
+
"test/pome.test.ts",
|
|
4563
|
+
"test/scoring.test.ts",
|
|
4564
|
+
"test/task.test.ts",
|
|
4565
|
+
"test/telemetry.test.ts",
|
|
4566
|
+
"test/url.test.ts",
|
|
4567
|
+
"tsconfig.json",
|
|
4568
|
+
"vitest.config.ts"
|
|
4569
|
+
]
|
|
4570
|
+
},
|
|
4571
|
+
{
|
|
4572
|
+
id: "langsmith",
|
|
4573
|
+
root: "integration-examples",
|
|
4574
|
+
rel: "integration-examples/langsmith",
|
|
4575
|
+
description: "Bundled Pome example: LangSmith's evaluate() gives every dataset row its own hosted Pome sandbox, and each Pome criterion comes back as its own LangSmith feedback key.",
|
|
4576
|
+
files: [
|
|
4577
|
+
".gitignore",
|
|
4578
|
+
"README.md",
|
|
4579
|
+
"package-lock.json",
|
|
4580
|
+
"package.json",
|
|
4581
|
+
"pome.json",
|
|
4582
|
+
"scripts/write-task.ts",
|
|
4583
|
+
"src/agent.ts",
|
|
4584
|
+
"src/dataset.ts",
|
|
4585
|
+
"src/index.ts",
|
|
4586
|
+
"src/langsmith.ts",
|
|
4587
|
+
"src/pome.ts",
|
|
4588
|
+
"src/scoring.ts",
|
|
4589
|
+
"src/task.ts",
|
|
4590
|
+
"src/url.ts",
|
|
4591
|
+
"tasks/lost-response-double-refund.md",
|
|
4592
|
+
"test/agent.test.ts",
|
|
4593
|
+
"test/dataset.test.ts",
|
|
4594
|
+
"test/fixtures/finalize-careful.json",
|
|
4595
|
+
"test/fixtures/finalize-double-refund.json",
|
|
4596
|
+
"test/index.test.ts",
|
|
4597
|
+
"test/langsmith-seam.test.ts",
|
|
4598
|
+
"test/langsmith.test.ts",
|
|
4599
|
+
"test/pome.test.ts",
|
|
4600
|
+
"test/scoring.test.ts",
|
|
4601
|
+
"test/task.test.ts",
|
|
4602
|
+
"test/url.test.ts",
|
|
4603
|
+
"tsconfig.json",
|
|
4604
|
+
"vitest.config.ts"
|
|
4605
|
+
]
|
|
4606
|
+
}
|
|
4607
|
+
];
|
|
4608
|
+
|
|
4609
|
+
// src/cli/init-example.ts
|
|
4610
|
+
var EXAMPLE_REPO = "pome-sh/digital-twins";
|
|
4611
|
+
var EXAMPLE_RAW_HOST = "https://raw.githubusercontent.com";
|
|
4612
|
+
var FETCH_CONCURRENCY = 8;
|
|
4613
|
+
var FULL_SHA = /^[0-9a-f]{40}$/;
|
|
4614
|
+
var ExampleScaffoldError = class extends Error {
|
|
4615
|
+
};
|
|
4616
|
+
function exampleIds() {
|
|
4617
|
+
return CATALOG_EXAMPLES.map((example) => example.id);
|
|
4618
|
+
}
|
|
4619
|
+
function findExample(id) {
|
|
4620
|
+
return CATALOG_EXAMPLES.find((example) => example.id === id.trim());
|
|
4621
|
+
}
|
|
4622
|
+
function unknownExampleMessage(id) {
|
|
4623
|
+
const width = Math.max(...CATALOG_EXAMPLES.map((example) => example.id.length));
|
|
4624
|
+
const lines = CATALOG_EXAMPLES.map(
|
|
4625
|
+
(example) => ` ${example.id.padEnd(width)} ${firstSentence(example.description)}`
|
|
4626
|
+
);
|
|
4627
|
+
return [
|
|
4628
|
+
`Unknown example "${id}". Available examples:`,
|
|
4629
|
+
"",
|
|
4630
|
+
...lines,
|
|
4631
|
+
"",
|
|
4632
|
+
`Run \`pome init --example ${CATALOG_EXAMPLES[0]?.id ?? "<id>"}\` to scaffold one.`
|
|
4633
|
+
].join("\n");
|
|
4634
|
+
}
|
|
4635
|
+
function firstSentence(description) {
|
|
4636
|
+
const stripped = description.replace(/^Bundled Pome example:\s*/i, "");
|
|
4637
|
+
const end = stripped.indexOf(". ");
|
|
4638
|
+
const sentence = (end === -1 ? stripped : stripped.slice(0, end + 1)).trim();
|
|
4639
|
+
return sentence.charAt(0).toUpperCase() + sentence.slice(1);
|
|
4640
|
+
}
|
|
4641
|
+
function resolveExampleRef(env = process.env) {
|
|
4642
|
+
const override = env.POME_EXAMPLE_REF?.trim();
|
|
4643
|
+
if (override) return override;
|
|
4644
|
+
const baked = "d34cec8ae64d618dee1e0121d5284c78177820cc".trim() ;
|
|
4645
|
+
return FULL_SHA.test(baked) ? baked : "main";
|
|
4646
|
+
}
|
|
4647
|
+
function rawUrlFor(example, file, ref) {
|
|
4648
|
+
const path = `${example.rel}/${file}`.split("/").map((segment) => encodeURIComponent(segment)).join("/");
|
|
4649
|
+
return `${EXAMPLE_RAW_HOST}/${EXAMPLE_REPO}/${encodeURIComponent(ref)}/${path}`;
|
|
4650
|
+
}
|
|
4651
|
+
async function fetchExampleFiles(example, ref, fetchImpl) {
|
|
4652
|
+
const out = /* @__PURE__ */ new Map();
|
|
4653
|
+
const queue = [...example.files];
|
|
4654
|
+
const worker = async () => {
|
|
4655
|
+
for (let file = queue.shift(); file !== void 0; file = queue.shift()) {
|
|
4656
|
+
const url = rawUrlFor(example, file, ref);
|
|
4657
|
+
let response;
|
|
4658
|
+
try {
|
|
4659
|
+
response = await fetchImpl(url);
|
|
4660
|
+
} catch (err) {
|
|
4661
|
+
throw new ExampleScaffoldError(
|
|
4662
|
+
`Could not reach ${url} (${err instanceof Error ? err.message : String(err)}). \`pome init --example\` downloads the example from GitHub; check your network or proxy and retry.`
|
|
4663
|
+
);
|
|
4664
|
+
}
|
|
4665
|
+
if (!response.ok) {
|
|
4666
|
+
throw new ExampleScaffoldError(
|
|
4667
|
+
`${url} returned HTTP ${response.status}. The example catalog in this CLI (${ref}) and the repository disagree about what files it has \u2014 upgrade with \`npm i -g @pome-sh/cli@latest\`.`
|
|
4668
|
+
);
|
|
4669
|
+
}
|
|
4670
|
+
out.set(file, Buffer.from(await response.arrayBuffer()));
|
|
4671
|
+
}
|
|
4672
|
+
};
|
|
4673
|
+
await Promise.all(
|
|
4674
|
+
Array.from({ length: Math.min(FETCH_CONCURRENCY, queue.length) }, () => worker())
|
|
4675
|
+
);
|
|
4676
|
+
return out;
|
|
4677
|
+
}
|
|
4678
|
+
async function assertEmptyTarget(target, id) {
|
|
4679
|
+
if (!existsSync(target)) return;
|
|
4680
|
+
const entries = await readdir(target);
|
|
4681
|
+
if (entries.length === 0) return;
|
|
4682
|
+
throw new ExampleScaffoldError(
|
|
4683
|
+
`${target} already exists and is not empty. Move it aside, or run \`pome init --example ${id}\` from a directory that does not have one.`
|
|
4684
|
+
);
|
|
4685
|
+
}
|
|
4686
|
+
async function scaffoldExample(options) {
|
|
4687
|
+
const example = findExample(options.id);
|
|
4688
|
+
if (!example) throw new ExampleScaffoldError(unknownExampleMessage(options.id));
|
|
4689
|
+
const ref = options.ref ?? resolveExampleRef();
|
|
4690
|
+
const target = join(options.cwd, example.id);
|
|
4691
|
+
await assertEmptyTarget(target, example.id);
|
|
4692
|
+
const files = await fetchExampleFiles(example, ref, options.fetchImpl ?? globalThis.fetch);
|
|
4693
|
+
for (const [file, contents] of files) {
|
|
4694
|
+
const destination = join(target, file);
|
|
4695
|
+
await mkdir(dirname(destination), { recursive: true });
|
|
4696
|
+
await writeFile(destination, contents);
|
|
4697
|
+
}
|
|
4698
|
+
return { dir: example.id, example, ref, fileCount: files.size };
|
|
4699
|
+
}
|
|
4700
|
+
function firstTaskFile(example) {
|
|
4701
|
+
return example.files.find((file) => file.startsWith("tasks/") && file.endsWith(".md"));
|
|
4702
|
+
}
|
|
4703
|
+
function scaffoldSummary(result) {
|
|
4704
|
+
const { example, dir, fileCount } = result;
|
|
4705
|
+
const header = `Scaffolded ${example.rel} into ./${dir} (${fileCount} files, from ${result.ref}).`;
|
|
4706
|
+
if (example.root === "integration-examples") {
|
|
4707
|
+
return `${header}
|
|
4708
|
+
Next steps:
|
|
4709
|
+
1. cd ${dir}
|
|
4710
|
+
2. npm install
|
|
4711
|
+
3. Read ${dir}/README.md \u2014 this example is driven by its own eval runner, not by \`pome run\`.`;
|
|
4712
|
+
}
|
|
4713
|
+
const task = firstTaskFile(example);
|
|
4714
|
+
return `${header}
|
|
4715
|
+
Next steps:
|
|
4716
|
+
1. cd ${dir}
|
|
4717
|
+
2. npm install
|
|
4718
|
+
3. pome login # one-time, opens the dashboard to sign in
|
|
4719
|
+
4. pome run ${task ?? "<task>.md"}`;
|
|
4720
|
+
}
|
|
4347
4721
|
var FIX_PROMPT_TEMPLATE_VERSION = "v1";
|
|
4348
4722
|
var MAX_EVENTS = 50;
|
|
4349
4723
|
var BODY_CHAR_LIMIT = 800;
|
|
@@ -4622,7 +4996,7 @@ var DEFAULT_AGENT_COMMAND = `node ${DEFAULT_AGENT_FILE}`;
|
|
|
4622
4996
|
var MANIFEST_SCHEMA_URL = "https://pome.sh/schemas/v1/pome.json";
|
|
4623
4997
|
var MAX_UNREADABLE_PATHS_SHOWN = 5;
|
|
4624
4998
|
function readPackageVersion() {
|
|
4625
|
-
if ("0.
|
|
4999
|
+
if ("0.35.0".length > 0) return "0.35.0";
|
|
4626
5000
|
try {
|
|
4627
5001
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
4628
5002
|
const candidates = [
|
|
@@ -4645,7 +5019,9 @@ function createProgram() {
|
|
|
4645
5019
|
program.name("pome").description(
|
|
4646
5020
|
"Test AI agents against digital twins of real SaaS APIs. Runs are recorded to app.pome.sh. Start with `pome demo`."
|
|
4647
5021
|
).version(PACKAGE_VERSION).showHelpAfterError("(add --help for usage)");
|
|
4648
|
-
program.command("init").summary("Set up Pome in this project").description(
|
|
5022
|
+
program.command("init").summary("Set up Pome in this project").description(
|
|
5023
|
+
"Create pome.json, plus starter files in a new project \u2014 or, with --example <id>, fetch a complete runnable example into ./<id>"
|
|
5024
|
+
).option(
|
|
4649
5025
|
"--sdk <name>",
|
|
4650
5026
|
"Scaffold for a specific agent SDK (claude | claude-managed). Adds the SDK-specific example file and pre-fills agent.framework so the dashboard badges runs correctly."
|
|
4651
5027
|
).option(
|
|
@@ -4654,8 +5030,38 @@ function createProgram() {
|
|
|
4654
5030
|
).option(
|
|
4655
5031
|
"--starter",
|
|
4656
5032
|
"Force the full starter library even in an existing project."
|
|
5033
|
+
).option(
|
|
5034
|
+
"--example <id>",
|
|
5035
|
+
`Scaffold a complete bundled example into ./<id> instead of a starter project. Ids: ${exampleIds().join(", ")}.`
|
|
4657
5036
|
).action(async (opts) => {
|
|
4658
5037
|
const sdk = opts.sdk?.trim();
|
|
5038
|
+
const exampleId = opts.example?.trim();
|
|
5039
|
+
if (exampleId !== void 0) {
|
|
5040
|
+
const conflicting = ["sdk", "bare", "starter"].filter(
|
|
5041
|
+
(flag) => opts[flag] !== void 0 && opts[flag] !== false
|
|
5042
|
+
);
|
|
5043
|
+
if (conflicting.length > 0) {
|
|
5044
|
+
console.error(
|
|
5045
|
+
`\`--example\` scaffolds a complete example and cannot be combined with ${conflicting.map((flag) => `--${flag}`).join(", ")}.`
|
|
5046
|
+
);
|
|
5047
|
+
process.exitCode = 2;
|
|
5048
|
+
return;
|
|
5049
|
+
}
|
|
5050
|
+
if (exampleId === "") {
|
|
5051
|
+
console.error(unknownExampleMessage(""));
|
|
5052
|
+
process.exitCode = 2;
|
|
5053
|
+
return;
|
|
5054
|
+
}
|
|
5055
|
+
try {
|
|
5056
|
+
const result = await scaffoldExample({ id: exampleId, cwd: process.cwd() });
|
|
5057
|
+
console.error(scaffoldSummary(result));
|
|
5058
|
+
} catch (err) {
|
|
5059
|
+
if (!(err instanceof ExampleScaffoldError)) throw err;
|
|
5060
|
+
console.error(err.message);
|
|
5061
|
+
process.exitCode = 2;
|
|
5062
|
+
}
|
|
5063
|
+
return;
|
|
5064
|
+
}
|
|
4659
5065
|
if (sdk !== void 0 && sdk !== "claude" && sdk !== "claude-managed") {
|
|
4660
5066
|
console.error(
|
|
4661
5067
|
`Unknown --sdk value "${opts.sdk}". Supported: claude, claude-managed.`
|