@pome-sh/cli 0.42.4 → 0.43.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.
@@ -4,7 +4,7 @@ export { DEFAULT_LINEAR_CLOCK, DEFAULT_LINEAR_EMAIL, DEFAULT_LINEAR_PORT, DEFAUL
4
4
  import './chunk-JWJYNAWI.js';
5
5
  import { routeInputDeclarer, mountDeclaredRoute, UndeclaredInputError } from './chunk-IZFM7W2V.js';
6
6
  import { loadMcpToolFixture, deriveMcpToolTable, openTwinDatabase, defineTwin, createApp } from './chunk-HRAD7MRX.js';
7
- import './chunk-6KJC4BTO.js';
7
+ import './chunk-5KFDRR53.js';
8
8
  import './chunk-SG6ZTIMT.js';
9
9
  import './chunk-FBSA5L36.js';
10
10
  import { createHmac, timingSafeEqual, createHash, randomBytes } from 'node:crypto';
@@ -4,7 +4,7 @@ import { defaultSeedState, parseSeed } from './chunk-YBWG5JK2.js';
4
4
  export { defaultSeedState, loadSeedFromEnv, parseSeed, seedSchema } from './chunk-YBWG5JK2.js';
5
5
  import { routeInputDeclarer, booleanInput, integerInput, mountDeclaredRoute, UndeclaredInputError } from './chunk-IZFM7W2V.js';
6
6
  import { loadMcpToolFixture, defineTwin, queryTokenResolver, formTokenResolver, deriveMcpToolTable, UnknownToolError, openTwinDatabase, createApp, typeDisagreements } from './chunk-HRAD7MRX.js';
7
- import './chunk-6KJC4BTO.js';
7
+ import './chunk-5KFDRR53.js';
8
8
  import './chunk-SG6ZTIMT.js';
9
9
  import './chunk-FBSA5L36.js';
10
10
  import { z, ZodError } from 'zod';
@@ -3,7 +3,7 @@ import { defaultSeedState, parseSeed } from './chunk-NBOQN5VX.js';
3
3
  export { defaultSeedState, parseSeed, seedSchema } from './chunk-NBOQN5VX.js';
4
4
  import { routeInputDeclarer, integerInput, mountDeclaredRoute, UndeclaredInputError, MalformedBodyError } from './chunk-IZFM7W2V.js';
5
5
  import { loadMcpToolFixture, defineTwin, twinBuildInfo, deriveMcpToolTable, UnknownToolError, openTwinDatabase, createApp, typeDisagreements } from './chunk-HRAD7MRX.js';
6
- import './chunk-6KJC4BTO.js';
6
+ import './chunk-5KFDRR53.js';
7
7
  import './chunk-SG6ZTIMT.js';
8
8
  import './chunk-FBSA5L36.js';
9
9
  import { z, ZodError } from 'zod';
@@ -1,6 +1,6 @@
1
1
  import { routeInputDeclarer, bracketedQuery, integerInput, booleanInput, mountDeclaredRoute, UndeclaredInputError } from './chunk-IZFM7W2V.js';
2
2
  import { loadMcpToolFixture, openTwinDatabase, defineTwin, twinBuildInfo, deriveMcpToolTable, failureInjectionMiddleware, createApp, recordedRequestHeaders, UnknownToolError } from './chunk-HRAD7MRX.js';
3
- import './chunk-6KJC4BTO.js';
3
+ import './chunk-5KFDRR53.js';
4
4
  import './chunk-SG6ZTIMT.js';
5
5
  import { defaultSeed, seedSchema } from './chunk-2K6BJ3PI.js';
6
6
  export { DEFAULT_API_KEY, DEFAULT_SID, defaultSeed, loadSeedFromEnv, parseSeed, seedSchema } from './chunk-2K6BJ3PI.js';
@@ -4,7 +4,7 @@ export { DEFAULT_GMAIL_AGENT_EMAIL, GmailError, SEARCH_MAILBOX_MESSAGE_BUDGET, a
4
4
  import './chunk-JWJYNAWI.js';
5
5
  import { routeInputDeclarer, integerInput, booleanInput, repeatedInput, mountDeclaredRoute, UndeclaredInputError, MalformedBodyError } from './chunk-IZFM7W2V.js';
6
6
  import { loadMcpToolFixture, deriveMcpToolTable, defineTwin, openTwinDatabase, createApp } from './chunk-HRAD7MRX.js';
7
- import './chunk-6KJC4BTO.js';
7
+ import './chunk-5KFDRR53.js';
8
8
  import './chunk-SG6ZTIMT.js';
9
9
  import './chunk-FBSA5L36.js';
10
10
  import { createHash, createHmac, timingSafeEqual, randomBytes } from 'node:crypto';
@@ -0,0 +1,6 @@
1
+ export { UnsupportedTwinError, bootTwin } from './chunk-5A6HHA54.js';
2
+ export { STRIPE_LOCAL_ACCOUNT_ID } from './chunk-ELIEDNF3.js';
3
+ import './chunk-HRAD7MRX.js';
4
+ import './chunk-5KFDRR53.js';
5
+ import './chunk-SG6ZTIMT.js';
6
+ import './chunk-FBSA5L36.js';
@@ -1,4 +1,4 @@
1
- import { TWIN_NAMES, isTwinName, TWIN_REGISTRY } from './chunk-RPPF2KDQ.js';
1
+ import { TWIN_NAMES, isTwinName, TWIN_REGISTRY } from './chunk-ELIEDNF3.js';
2
2
  import { writeFile } from 'node:fs/promises';
3
3
 
4
4
  async function generateSeedFile(twins) {
@@ -1,8 +1,8 @@
1
- import { readSeedFileText, seedForTwin, parseSeedFileText, soleTwinOf, twinsNamedBy } from './chunk-VPXIGCZW.js';
2
- import { bootTwin } from './chunk-5NPGY73F.js';
3
- import { TWIN_REGISTRY, isTwinName, TWIN_NAMES, defaultPortFor } from './chunk-RPPF2KDQ.js';
1
+ import { readSeedFileText, seedForTwin, parseSeedFileText, soleTwinOf, twinsNamedBy } from './chunk-3YCX3KUL.js';
2
+ import { bootTwin } from './chunk-5A6HHA54.js';
3
+ import { TWIN_REGISTRY, isTwinName, TWIN_NAMES, defaultPortFor } from './chunk-ELIEDNF3.js';
4
4
  import './chunk-HRAD7MRX.js';
5
- import './chunk-6KJC4BTO.js';
5
+ import './chunk-5KFDRR53.js';
6
6
  import './chunk-SG6ZTIMT.js';
7
7
  import './chunk-FBSA5L36.js';
8
8
  import { randomBytes } from 'node:crypto';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pome-sh/cli",
3
- "version": "0.42.4",
3
+ "version": "0.43.0",
4
4
  "description": "Test AI agents against digital twins of real SaaS APIs. Records tool-call traces and scores them on pome.sh.",
5
5
  "keywords": [
6
6
  "ai",
@@ -50,7 +50,6 @@
50
50
  "typecheck": "tsc -p tsconfig.json --noEmit",
51
51
  "gate:recorder-overhead": "tsx scripts/recorder-overhead-gate.ts",
52
52
  "gate:agent-trace-overhead": "tsx scripts/overhead-gate.ts",
53
- "gate:cas-adapter-acceptance": "tsx scripts/cas-adapter-acceptance.ts",
54
53
  "emit:manifest-schema": "node scripts/emit-manifest-schema.mjs",
55
54
  "check:manifest-schema": "node scripts/emit-manifest-schema.mjs --check"
56
55
  },
@@ -1,408 +0,0 @@
1
- import { DemoCapacityError, capacityMarkerLine, capacityKindFrom, capacityLabel } from './chunk-ZX4WNSZ5.js';
2
- import { z } from 'zod';
3
- import { request } from 'node:http';
4
- import { connect as connect$1 } from 'node:net';
5
- import { connect } from 'node:tls';
6
-
7
- function isLoopbackHost(host) {
8
- const value = host.trim().toLowerCase();
9
- if (value === "localhost" || value.endsWith(".localhost")) return true;
10
- if (value === "::1" || value === "[::1]") return true;
11
- return /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(value);
12
- }
13
- function matchesNoProxy(host, noProxy) {
14
- if (!noProxy) return false;
15
- const candidate = host.trim().toLowerCase();
16
- return noProxy.split(",").map((entry) => entry.trim().toLowerCase()).filter((entry) => entry.length > 0).some(
17
- (entry) => entry === "*" || candidate === entry || candidate.endsWith(entry.startsWith(".") ? entry : `.${entry}`)
18
- );
19
- }
20
- async function postJsonMaybeViaProxy(options) {
21
- const target = new URL(options.url);
22
- const useProxy = Boolean(options.proxyUrl) && (options.forceProxy === true || !isLoopbackHost(target.hostname) && !matchesNoProxy(target.hostname, options.noProxy));
23
- if (!useProxy) {
24
- const ctrl = new AbortController();
25
- const timer = setTimeout(() => ctrl.abort(), options.timeoutMs ?? 6e4);
26
- try {
27
- const res = await fetch(options.url, {
28
- method: "POST",
29
- headers: { ...options.headers, "content-type": "application/json" },
30
- body: JSON.stringify(options.body),
31
- signal: ctrl.signal
32
- });
33
- return { status: res.status, bodyText: await res.text() };
34
- } finally {
35
- clearTimeout(timer);
36
- }
37
- }
38
- return postJsonThroughConnectProxy(target, options);
39
- }
40
- async function postJsonThroughConnectProxy(target, options) {
41
- const proxy = new URL(options.proxyUrl);
42
- const targetPort = Number(target.port || (target.protocol === "https:" ? 443 : 80));
43
- const timeoutMs = options.timeoutMs ?? 6e4;
44
- const rawSocket = await connectTunnel(
45
- proxy.hostname,
46
- Number(proxy.port || 80),
47
- target.hostname,
48
- targetPort,
49
- timeoutMs
50
- );
51
- const socket = target.protocol === "https:" ? await new Promise((resolve, reject) => {
52
- const tlsSocket = connect(
53
- { socket: rawSocket, servername: target.hostname },
54
- () => resolve(tlsSocket)
55
- );
56
- tlsSocket.once("error", reject);
57
- }) : rawSocket;
58
- return new Promise((resolve, reject) => {
59
- const payload = JSON.stringify(options.body);
60
- const req = request(
61
- {
62
- createConnection: () => socket,
63
- method: "POST",
64
- host: target.hostname,
65
- port: targetPort,
66
- path: `${target.pathname}${target.search}`,
67
- headers: {
68
- ...options.headers,
69
- host: target.host,
70
- "content-type": "application/json",
71
- "content-length": Buffer.byteLength(payload),
72
- connection: "close"
73
- },
74
- timeout: timeoutMs
75
- },
76
- (res) => {
77
- let bodyText = "";
78
- res.setEncoding("utf8");
79
- res.on("data", (chunk) => {
80
- bodyText += chunk;
81
- });
82
- res.on("end", () => {
83
- resolve({ status: res.statusCode ?? 0, bodyText });
84
- });
85
- res.on("error", reject);
86
- }
87
- );
88
- req.on("timeout", () => {
89
- req.destroy(new Error(`request to ${target.host} timed out after ${timeoutMs}ms`));
90
- });
91
- req.on("error", (err) => {
92
- socket.destroy();
93
- reject(err);
94
- });
95
- req.end(payload);
96
- });
97
- }
98
- function connectTunnel(proxyHost, proxyPort, targetHost, targetPort, timeoutMs) {
99
- return new Promise((resolve, reject) => {
100
- const sock = connect$1({ host: proxyHost, port: proxyPort });
101
- let buf = "";
102
- let settled = false;
103
- const timer = setTimeout(() => {
104
- if (settled) return;
105
- settled = true;
106
- sock.destroy();
107
- reject(new Error(`CONNECT to ${targetHost}:${targetPort} timed out after ${timeoutMs}ms`));
108
- }, timeoutMs);
109
- const fail = (err) => {
110
- if (settled) return;
111
- settled = true;
112
- clearTimeout(timer);
113
- sock.destroy();
114
- reject(err);
115
- };
116
- sock.once("error", fail);
117
- const onData = (chunk) => {
118
- buf += chunk.toString("utf8");
119
- const headerEnd = buf.indexOf("\r\n\r\n");
120
- if (headerEnd === -1) return;
121
- sock.off("data", onData);
122
- if (!/^HTTP\/1\.[01] 200/.test(buf)) {
123
- fail(new Error(`CONNECT ${targetHost}:${targetPort} refused: ${buf.split("\r\n")[0]}`));
124
- return;
125
- }
126
- settled = true;
127
- clearTimeout(timer);
128
- sock.pause();
129
- const rest = Buffer.from(buf.slice(headerEnd + 4), "utf8");
130
- if (rest.length > 0) sock.unshift(rest);
131
- sock.resume();
132
- resolve(sock);
133
- };
134
- sock.on("data", onData);
135
- sock.write(
136
- `CONNECT ${targetHost}:${targetPort} HTTP/1.1\r
137
- Host: ${targetHost}:${targetPort}\r
138
- \r
139
- `
140
- );
141
- });
142
- }
143
-
144
- // src/demo/gateway.ts
145
- var gatewayResponseSchema = z.object({
146
- text: z.string(),
147
- tool_calls: z.array(
148
- z.object({
149
- id: z.string(),
150
- name: z.string(),
151
- input: z.unknown()
152
- })
153
- ),
154
- finish_reason: z.string(),
155
- usage: z.object({
156
- input_tokens: z.number(),
157
- output_tokens: z.number()
158
- }).optional()
159
- });
160
- var DemoGatewayError = class extends Error {
161
- constructor(message, status) {
162
- super(message);
163
- this.status = status;
164
- this.name = "DemoGatewayError";
165
- }
166
- status;
167
- };
168
- async function callDemoGateway(options) {
169
- const { status, bodyText } = await postJsonMaybeViaProxy({
170
- url: options.gatewayUrl,
171
- headers: { authorization: `Bearer ${options.demoToken}` },
172
- body: {
173
- task_name: options.taskName,
174
- messages: options.messages,
175
- ...options.tools && options.tools.length > 0 ? { tools: options.tools } : {}
176
- },
177
- proxyUrl: options.proxyUrl,
178
- noProxy: options.noProxy,
179
- timeoutMs: options.timeoutMs ?? 12e4,
180
- forceProxy: options.forceProxyForTest
181
- });
182
- let json = {};
183
- try {
184
- json = bodyText.length ? JSON.parse(bodyText) : {};
185
- } catch {
186
- throw new DemoGatewayError(
187
- `demo gateway returned non-JSON (status ${status})`,
188
- status
189
- );
190
- }
191
- if (status < 200 || status >= 300) {
192
- const envelope = json.error;
193
- const kind = capacityKindFrom(status, envelope?.details?.kind);
194
- if (kind) {
195
- throw new DemoCapacityError(kind, envelope?.message ?? capacityLabel(kind));
196
- }
197
- throw new DemoGatewayError(
198
- envelope?.message ?? `demo gateway \u2192 HTTP ${status}`,
199
- status
200
- );
201
- }
202
- const parsed = gatewayResponseSchema.safeParse(json);
203
- if (!parsed.success) {
204
- throw new DemoGatewayError(
205
- `demo gateway returned an unexpected shape: ${parsed.error.message}`,
206
- status
207
- );
208
- }
209
- return parsed.data;
210
- }
211
-
212
- // src/demo/agent.ts
213
- var MAX_TURNS = 12;
214
- var DEMO_AGENT_TOOLS = [
215
- {
216
- name: "list_open_issues",
217
- description: "List the open issues in the repository you are triaging. Returns number, title, body, and current labels for each.",
218
- input_schema: {
219
- type: "object",
220
- properties: {},
221
- additionalProperties: false
222
- }
223
- },
224
- {
225
- name: "add_label",
226
- description: "Apply an EXISTING label to an issue by number. Fails if the label does not exist in the repository.",
227
- input_schema: {
228
- type: "object",
229
- properties: {
230
- issue_number: { type: "number", description: "Issue number, e.g. 1" },
231
- label: { type: "string", description: "Name of an existing label" }
232
- },
233
- required: ["issue_number", "label"],
234
- additionalProperties: false
235
- }
236
- },
237
- {
238
- name: "comment_on_issue",
239
- description: "Leave one comment on an issue by number.",
240
- input_schema: {
241
- type: "object",
242
- properties: {
243
- issue_number: { type: "number", description: "Issue number, e.g. 1" },
244
- body: { type: "string", description: "Comment body (markdown)" }
245
- },
246
- required: ["issue_number", "body"],
247
- additionalProperties: false
248
- }
249
- }
250
- ];
251
- function readDemoAgentEnv(env) {
252
- const required = (name) => {
253
- const value = env[name]?.trim();
254
- if (!value) throw new Error(`${name} is required for pome demo-agent`);
255
- return value;
256
- };
257
- return {
258
- task: required("POME_TASK"),
259
- twinRestUrl: required("POME_GITHUB_REST_URL"),
260
- twinAuthToken: required("POME_AUTH_TOKEN"),
261
- gatewayUrl: required("POME_DEMO_LLM_URL"),
262
- demoToken: required("POME_DEMO_TOKEN"),
263
- taskName: required("POME_DEMO_TASK_NAME"),
264
- repo: required("POME_DEMO_REPO"),
265
- proxyUrl: env.HTTPS_PROXY ?? env.HTTP_PROXY,
266
- noProxy: env.NO_PROXY
267
- };
268
- }
269
- async function twinFetch(agentEnv, path, init) {
270
- const res = await fetch(`${agentEnv.twinRestUrl}${path}`, {
271
- method: init?.method ?? "GET",
272
- headers: {
273
- authorization: `Bearer ${agentEnv.twinAuthToken}`,
274
- ...init?.body !== void 0 ? { "content-type": "application/json" } : {}
275
- },
276
- body: init?.body !== void 0 ? JSON.stringify(init.body) : void 0
277
- });
278
- const text = await res.text();
279
- if (!res.ok) {
280
- throw new Error(
281
- `${init?.method ?? "GET"} ${path} \u2192 ${res.status}: ${text.slice(0, 300)}`
282
- );
283
- }
284
- return text.length ? JSON.parse(text) : {};
285
- }
286
- async function executeDemoTool(agentEnv, name, input) {
287
- const [owner, repo] = agentEnv.repo.split("/");
288
- const args = input ?? {};
289
- try {
290
- switch (name) {
291
- case "list_open_issues": {
292
- const issues = await twinFetch(
293
- agentEnv,
294
- `/repos/${owner}/${repo}/issues?state=open`
295
- );
296
- return {
297
- output: issues.map((issue) => ({
298
- number: issue.number,
299
- title: issue.title,
300
- body: issue.body,
301
- labels: (issue.labels ?? []).map(
302
- (label) => typeof label === "string" ? label : label.name
303
- )
304
- })),
305
- isError: false
306
- };
307
- }
308
- case "add_label": {
309
- const issueNumber = Number(args.issue_number);
310
- const label = String(args.label ?? "");
311
- if (!Number.isInteger(issueNumber) || label.length === 0) {
312
- return { output: "add_label requires issue_number and label", isError: true };
313
- }
314
- await twinFetch(agentEnv, `/repos/${owner}/${repo}/issues/${issueNumber}/labels`, {
315
- method: "POST",
316
- body: { labels: [label] }
317
- });
318
- return { output: `applied label "${label}" to issue #${issueNumber}`, isError: false };
319
- }
320
- case "comment_on_issue": {
321
- const issueNumber = Number(args.issue_number);
322
- const body = String(args.body ?? "");
323
- if (!Number.isInteger(issueNumber) || body.length === 0) {
324
- return { output: "comment_on_issue requires issue_number and body", isError: true };
325
- }
326
- await twinFetch(agentEnv, `/repos/${owner}/${repo}/issues/${issueNumber}/comments`, {
327
- method: "POST",
328
- body: { body }
329
- });
330
- return { output: `commented on issue #${issueNumber}`, isError: false };
331
- }
332
- default:
333
- return { output: `unknown tool: ${name}`, isError: true };
334
- }
335
- } catch (err) {
336
- return {
337
- output: err instanceof Error ? err.message : String(err),
338
- isError: true
339
- };
340
- }
341
- }
342
- async function runDemoAgent(agentEnv, io) {
343
- const messages = [{ role: "user", content: agentEnv.task }];
344
- try {
345
- for (let turn = 0; turn < MAX_TURNS; turn += 1) {
346
- const response = await callDemoGateway({
347
- gatewayUrl: agentEnv.gatewayUrl,
348
- demoToken: agentEnv.demoToken,
349
- taskName: agentEnv.taskName,
350
- messages,
351
- tools: DEMO_AGENT_TOOLS,
352
- proxyUrl: agentEnv.proxyUrl,
353
- noProxy: agentEnv.noProxy
354
- });
355
- if (response.tool_calls.length === 0) {
356
- io.log(response.text.trim().length > 0 ? response.text.trim() : "(done)");
357
- return 0;
358
- }
359
- const assistantParts = [];
360
- if (response.text.trim().length > 0) {
361
- assistantParts.push({ type: "text", text: response.text });
362
- }
363
- for (const call of response.tool_calls) {
364
- assistantParts.push({
365
- type: "tool-call",
366
- toolCallId: call.id,
367
- toolName: call.name,
368
- input: call.input
369
- });
370
- }
371
- messages.push({ role: "assistant", content: assistantParts });
372
- const resultParts = [];
373
- for (const call of response.tool_calls) {
374
- const result = await executeDemoTool(agentEnv, call.name, call.input);
375
- resultParts.push({
376
- type: "tool-result",
377
- toolCallId: call.id,
378
- toolName: call.name,
379
- output: result.isError ? { type: "error-text", value: String(result.output) } : { type: "json", value: result.output }
380
- });
381
- }
382
- messages.push({ role: "tool", content: resultParts });
383
- }
384
- io.error(`demo agent gave up after ${MAX_TURNS} model calls without finishing`);
385
- return 1;
386
- } catch (err) {
387
- if (err instanceof DemoCapacityError) {
388
- io.error(capacityMarkerLine(err.kind));
389
- io.error(err.message);
390
- return 42;
391
- }
392
- io.error(err instanceof Error ? err.message : String(err));
393
- return 1;
394
- }
395
- }
396
- async function runDemoAgentCommand() {
397
- if (process.env.POME_PREFLIGHT === "1") {
398
- console.log("preflight ok");
399
- return 0;
400
- }
401
- const agentEnv = readDemoAgentEnv(process.env);
402
- return runDemoAgent(agentEnv, {
403
- log: (line) => console.log(line),
404
- error: (line) => console.error(line)
405
- });
406
- }
407
-
408
- export { DEMO_AGENT_TOOLS, executeDemoTool, readDemoAgentEnv, runDemoAgent, runDemoAgentCommand };