@pome-sh/cli 0.26.13 → 0.27.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 (34) hide show
  1. package/dist/build-info.json +3 -3
  2. package/dist/{checks-3LVRPHOK.js → checks-QM7QOJ6U.js} +2 -2
  3. package/dist/{chunk-NJ246QPJ.js → chunk-3T5XN64P.js} +35 -33
  4. package/dist/chunk-CF6EIU2U.js +51 -0
  5. package/dist/{chunk-ANKO3RCB.js → chunk-CTA54N4K.js} +5 -5
  6. package/dist/{chunk-CFXEETE3.js → chunk-E665XWYU.js} +2 -49
  7. package/dist/{chunk-IZIZC7ZW.js → chunk-G6GOCYIT.js} +23 -21
  8. package/dist/{chunk-QXQAVKTE.js → chunk-HJX25USP.js} +14 -1
  9. package/dist/{chunk-KIXYRPVY.js → chunk-IK2F7ZA3.js} +2 -2
  10. package/dist/{chunk-EIUCTFQV.js → chunk-JE4H5ODK.js} +16 -11
  11. package/dist/{chunk-6IVXTU67.js → chunk-MQE6DKIK.js} +4 -3
  12. package/dist/{chunk-FQGR7KDT.js → chunk-N74LP4QH.js} +2 -2
  13. package/dist/chunk-SLTBPJKZ.js +522 -0
  14. package/dist/chunk-ZDS25NS5.js +141 -0
  15. package/dist/{runDemo-XO5R5QTM.js → runDemo-O67ASC54.js} +11 -10
  16. package/dist/{runTrialGroup-CLJJOO4J.js → runTrialGroup-V3HB57YI.js} +9 -8
  17. package/dist/seed-3ZTWKLBE.js +1 -0
  18. package/dist/seed-BG5HMSBM.js +1 -0
  19. package/dist/seed-IIMBJHAJ.js +1 -0
  20. package/dist/seed-NR6RUKXV.js +1 -0
  21. package/dist/seed-YWDTT2WL.js +2 -0
  22. package/dist/server-DMLORMOV.js +4 -0
  23. package/dist/src/cli/main.js +32 -22
  24. package/dist/{src-JJNS46T6.js → src-56Y2R7ZQ.js} +4 -3
  25. package/dist/{src-Q4JNJE5S.js → src-JRBHNT4Y.js} +4 -3
  26. package/dist/{src-GWA7QVQS.js → src-KSLAF3I4.js} +4 -3
  27. package/dist/{src-FXRQSKBK.js → src-PW7U25ZX.js} +6 -518
  28. package/dist/{src-L6F5YXSP.js → src-SKCWAMVQ.js} +5 -138
  29. package/dist/twinHarness-YOVJR72F.js +6 -0
  30. package/dist/{twinStart-WIT4UVAC.js → twinStart-PDL53BY5.js} +58 -5
  31. package/package.json +1 -1
  32. package/dist/server-TK5YBK6E.js +0 -3
  33. package/dist/twinHarness-6NVAKIOB.js +0 -5
  34. package/dist/{run-CFA4LZWQ.js → run-WONFTZS3.js} +1 -1
@@ -0,0 +1,522 @@
1
+ import { failureInjectionRuleSchema } from './chunk-CF6EIU2U.js';
2
+ import { z } from 'zod';
3
+ import { randomUUID, randomBytes } from 'node:crypto';
4
+
5
+ var BASE62 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
6
+ var ID_PREFIXES = {
7
+ customer: "cus_",
8
+ payment_method: "pm_",
9
+ payment_intent: "pi_",
10
+ charge: "ch_",
11
+ refund: "re_",
12
+ product: "prod_",
13
+ price: "price_",
14
+ subscription: "sub_",
15
+ subscription_item: "si_",
16
+ setup_intent: "seti_",
17
+ checkout_session: "cs_test_",
18
+ webhook_endpoint: "we_",
19
+ event: "evt_",
20
+ shared_payment_issued: "spt_",
21
+ shared_payment_granted: "spt_",
22
+ profile: "profile_",
23
+ balance_transaction: "txn_",
24
+ // API keys are minted via api-keys.ts but the prefix lives here for parity.
25
+ api_key: "sk_test_pome_",
26
+ api_key_restricted: "rk_test_pome_"
27
+ };
28
+ function randomBase62(count) {
29
+ const buf = randomBytes(count * 2);
30
+ let out = "";
31
+ let i = 0;
32
+ while (out.length < count && i < buf.length) {
33
+ const byte = buf[i++];
34
+ if (byte < 248) {
35
+ out += BASE62[byte % 62];
36
+ }
37
+ }
38
+ if (out.length < count) {
39
+ out += randomBase62(count - out.length);
40
+ }
41
+ return out;
42
+ }
43
+ function newId(kind) {
44
+ return `${ID_PREFIXES[kind]}${randomBase62(24)}`;
45
+ }
46
+ function newClientSecret(piId) {
47
+ return `${piId}_secret_${randomBase62(24)}`;
48
+ }
49
+ function newApiKey() {
50
+ return newId("api_key");
51
+ }
52
+ function nowIso() {
53
+ return (/* @__PURE__ */ new Date()).toISOString();
54
+ }
55
+ function nowUnix() {
56
+ return Math.floor(Date.now() / 1e3);
57
+ }
58
+ function requestId() {
59
+ return `req_${randomUUID()}`;
60
+ }
61
+
62
+ // ../packages/twin-stripe/dist/src/api-keys.js
63
+ function mintApiKey(db, input) {
64
+ const key = input.key ?? newApiKey();
65
+ const account_id = input.account_id ?? `acct_${input.sid}`;
66
+ const created_at = nowIso();
67
+ db.prepare(`INSERT INTO api_keys (key, sid, account_id, created_at, revoked_at)
68
+ VALUES (?, ?, ?, ?, NULL)
69
+ ON CONFLICT(key) DO UPDATE SET
70
+ sid = excluded.sid,
71
+ account_id = excluded.account_id,
72
+ revoked_at = NULL`).run(key, input.sid, account_id, created_at);
73
+ return { key, sid: input.sid, account_id, created_at, revoked_at: null };
74
+ }
75
+ function revokeApiKey(db, key) {
76
+ db.prepare(`UPDATE api_keys SET revoked_at = ? WHERE key = ?`).run(nowIso(), key);
77
+ }
78
+ function resolveSidFromKey(db, token) {
79
+ const row = db.prepare(`SELECT key, sid, account_id, created_at, revoked_at
80
+ FROM api_keys
81
+ WHERE key = ? AND revoked_at IS NULL`).get(token);
82
+ if (!row)
83
+ return void 0;
84
+ return { sid: row.sid, account_id: row.account_id };
85
+ }
86
+ function looksLikeApiKey(token) {
87
+ return token.startsWith("sk_test_pome_") || token.startsWith("rk_test_pome_") || // Tolerate raw Stripe-style sk_test_* / rk_test_* in case a downstream
88
+ // user mints their own non-pome-prefixed test keys via the admin API.
89
+ token.startsWith("sk_test_") || token.startsWith("rk_test_");
90
+ }
91
+
92
+ // ../packages/twin-stripe/dist/src/domain/schema.js
93
+ var STRIPE_TABLES_SQL = `
94
+ CREATE TABLE IF NOT EXISTS payment_intents (
95
+ id TEXT PRIMARY KEY,
96
+ account_id TEXT NOT NULL,
97
+ amount INTEGER NOT NULL,
98
+ currency TEXT NOT NULL,
99
+ status TEXT NOT NULL,
100
+ payment_method_types_json TEXT NOT NULL,
101
+ next_action_json TEXT,
102
+ latest_charge_id TEXT,
103
+ capture_method TEXT NOT NULL DEFAULT 'automatic',
104
+ confirmation_method TEXT NOT NULL DEFAULT 'automatic',
105
+ idempotency_key TEXT,
106
+ metadata_json TEXT NOT NULL DEFAULT '{}',
107
+ crypto_deposit_json TEXT,
108
+ client_secret TEXT NOT NULL,
109
+ created INTEGER NOT NULL,
110
+ updated INTEGER NOT NULL,
111
+ canceled_at INTEGER,
112
+ captured_at INTEGER,
113
+ payment_method_id TEXT,
114
+ customer_id TEXT,
115
+ last_payment_error_json TEXT
116
+ );
117
+
118
+ CREATE INDEX IF NOT EXISTS idx_payment_intents_created ON payment_intents(created);
119
+ CREATE INDEX IF NOT EXISTS idx_payment_intents_status ON payment_intents(status);
120
+ CREATE INDEX IF NOT EXISTS idx_payment_intents_account_id ON payment_intents(account_id);
121
+
122
+ CREATE TABLE IF NOT EXISTS charges (
123
+ id TEXT PRIMARY KEY,
124
+ account_id TEXT NOT NULL,
125
+ payment_intent_id TEXT NOT NULL,
126
+ amount INTEGER NOT NULL,
127
+ amount_captured INTEGER NOT NULL DEFAULT 0,
128
+ amount_refunded INTEGER NOT NULL DEFAULT 0,
129
+ status TEXT NOT NULL,
130
+ balance_transaction_id TEXT,
131
+ captured INTEGER NOT NULL DEFAULT 0,
132
+ currency TEXT NOT NULL,
133
+ created INTEGER NOT NULL,
134
+ payment_method_id TEXT,
135
+ payment_method_details_json TEXT,
136
+ failure_code TEXT,
137
+ failure_decline_code TEXT,
138
+ failure_message TEXT,
139
+ customer_id TEXT,
140
+ FOREIGN KEY (payment_intent_id) REFERENCES payment_intents(id) ON DELETE CASCADE
141
+ );
142
+
143
+ CREATE INDEX IF NOT EXISTS idx_charges_pi ON charges(payment_intent_id);
144
+ CREATE INDEX IF NOT EXISTS idx_charges_created ON charges(created);
145
+ CREATE INDEX IF NOT EXISTS idx_charges_account_id ON charges(account_id);
146
+
147
+ CREATE TABLE IF NOT EXISTS balance_transactions (
148
+ id TEXT PRIMARY KEY,
149
+ account_id TEXT NOT NULL,
150
+ type TEXT NOT NULL,
151
+ amount INTEGER NOT NULL,
152
+ fee INTEGER NOT NULL DEFAULT 0,
153
+ net INTEGER NOT NULL,
154
+ currency TEXT NOT NULL,
155
+ source_id TEXT,
156
+ source_type TEXT,
157
+ available_on INTEGER NOT NULL,
158
+ status TEXT NOT NULL DEFAULT 'available',
159
+ created INTEGER NOT NULL
160
+ );
161
+
162
+ CREATE INDEX IF NOT EXISTS idx_balance_tx_created ON balance_transactions(created);
163
+ CREATE INDEX IF NOT EXISTS idx_balance_tx_source ON balance_transactions(source_id);
164
+ CREATE INDEX IF NOT EXISTS idx_balance_tx_account_id ON balance_transactions(account_id);
165
+
166
+ CREATE TABLE IF NOT EXISTS events (
167
+ id TEXT PRIMARY KEY,
168
+ account_id TEXT NOT NULL,
169
+ type TEXT NOT NULL,
170
+ data_json TEXT NOT NULL,
171
+ request_idempotency_key TEXT,
172
+ livemode INTEGER NOT NULL DEFAULT 0,
173
+ api_version TEXT NOT NULL,
174
+ created INTEGER NOT NULL
175
+ );
176
+
177
+ CREATE INDEX IF NOT EXISTS idx_events_type ON events(type);
178
+ CREATE INDEX IF NOT EXISTS idx_events_created ON events(created);
179
+ CREATE INDEX IF NOT EXISTS idx_events_account_id ON events(account_id);
180
+
181
+ CREATE TABLE IF NOT EXISTS refunds (
182
+ id TEXT PRIMARY KEY,
183
+ account_id TEXT NOT NULL,
184
+ charge_id TEXT NOT NULL,
185
+ payment_intent_id TEXT NOT NULL,
186
+ amount INTEGER NOT NULL,
187
+ currency TEXT NOT NULL,
188
+ status TEXT NOT NULL,
189
+ reason TEXT,
190
+ balance_transaction_id TEXT,
191
+ idempotency_key TEXT,
192
+ created INTEGER NOT NULL,
193
+ FOREIGN KEY (charge_id) REFERENCES charges(id) ON DELETE CASCADE
194
+ );
195
+
196
+ CREATE INDEX IF NOT EXISTS idx_refunds_charge ON refunds(charge_id);
197
+ CREATE INDEX IF NOT EXISTS idx_refunds_payment_intent ON refunds(payment_intent_id);
198
+ CREATE INDEX IF NOT EXISTS idx_refunds_created ON refunds(created);
199
+ CREATE INDEX IF NOT EXISTS idx_refunds_account_id ON refunds(account_id);
200
+
201
+ CREATE TABLE IF NOT EXISTS customers (
202
+ id TEXT PRIMARY KEY,
203
+ account_id TEXT NOT NULL,
204
+ name TEXT,
205
+ email TEXT,
206
+ description TEXT,
207
+ phone TEXT,
208
+ metadata_json TEXT NOT NULL DEFAULT '{}',
209
+ deleted INTEGER NOT NULL DEFAULT 0,
210
+ created INTEGER NOT NULL
211
+ );
212
+
213
+ CREATE INDEX IF NOT EXISTS idx_customers_created ON customers(created);
214
+ CREATE INDEX IF NOT EXISTS idx_customers_email ON customers(email);
215
+ CREATE INDEX IF NOT EXISTS idx_customers_account_id ON customers(account_id);
216
+
217
+ CREATE TABLE IF NOT EXISTS payment_methods (
218
+ id TEXT PRIMARY KEY,
219
+ account_id TEXT NOT NULL,
220
+ type TEXT NOT NULL,
221
+ card_brand TEXT NOT NULL,
222
+ card_last4 TEXT NOT NULL,
223
+ card_exp_month INTEGER NOT NULL,
224
+ card_exp_year INTEGER NOT NULL,
225
+ card_fingerprint TEXT NOT NULL,
226
+ customer_id TEXT,
227
+ detached INTEGER NOT NULL DEFAULT 0,
228
+ created INTEGER NOT NULL
229
+ );
230
+
231
+ CREATE INDEX IF NOT EXISTS idx_payment_methods_customer ON payment_methods(customer_id);
232
+ CREATE INDEX IF NOT EXISTS idx_payment_methods_created ON payment_methods(created);
233
+ CREATE INDEX IF NOT EXISTS idx_payment_methods_account_id ON payment_methods(account_id);
234
+
235
+ -- Billing tables (warm surfaces, shape tier): plain stored rows served
236
+ -- back in Stripe shape. No invoices table \u2014 invoices are reads-only and
237
+ -- nothing in the twin mints one (loud shape divergence, see FIDELITY.md).
238
+
239
+ CREATE TABLE IF NOT EXISTS products (
240
+ id TEXT PRIMARY KEY,
241
+ account_id TEXT NOT NULL,
242
+ name TEXT NOT NULL,
243
+ description TEXT,
244
+ active INTEGER NOT NULL DEFAULT 1,
245
+ metadata_json TEXT NOT NULL DEFAULT '{}',
246
+ created INTEGER NOT NULL,
247
+ updated INTEGER NOT NULL
248
+ );
249
+
250
+ CREATE INDEX IF NOT EXISTS idx_products_created ON products(created);
251
+ CREATE INDEX IF NOT EXISTS idx_products_account_id ON products(account_id);
252
+
253
+ CREATE TABLE IF NOT EXISTS prices (
254
+ id TEXT PRIMARY KEY,
255
+ account_id TEXT NOT NULL,
256
+ product_id TEXT NOT NULL,
257
+ currency TEXT NOT NULL,
258
+ unit_amount INTEGER,
259
+ recurring_interval TEXT,
260
+ recurring_interval_count INTEGER,
261
+ active INTEGER NOT NULL DEFAULT 1,
262
+ nickname TEXT,
263
+ lookup_key TEXT,
264
+ metadata_json TEXT NOT NULL DEFAULT '{}',
265
+ created INTEGER NOT NULL
266
+ );
267
+
268
+ CREATE INDEX IF NOT EXISTS idx_prices_created ON prices(created);
269
+ CREATE INDEX IF NOT EXISTS idx_prices_product ON prices(product_id);
270
+ CREATE INDEX IF NOT EXISTS idx_prices_account_id ON prices(account_id);
271
+
272
+ CREATE TABLE IF NOT EXISTS subscriptions (
273
+ id TEXT PRIMARY KEY,
274
+ account_id TEXT NOT NULL,
275
+ customer_id TEXT NOT NULL,
276
+ status TEXT NOT NULL,
277
+ items_json TEXT NOT NULL,
278
+ cancel_at_period_end INTEGER NOT NULL DEFAULT 0,
279
+ canceled_at INTEGER,
280
+ ended_at INTEGER,
281
+ metadata_json TEXT NOT NULL DEFAULT '{}',
282
+ created INTEGER NOT NULL
283
+ );
284
+
285
+ CREATE INDEX IF NOT EXISTS idx_subscriptions_created ON subscriptions(created);
286
+ CREATE INDEX IF NOT EXISTS idx_subscriptions_customer ON subscriptions(customer_id);
287
+ CREATE INDEX IF NOT EXISTS idx_subscriptions_account_id ON subscriptions(account_id);
288
+ `;
289
+ var STRIPE_TABLES = [
290
+ "refunds",
291
+ "events",
292
+ "balance_transactions",
293
+ "charges",
294
+ "payment_intents",
295
+ "payment_methods",
296
+ "customers",
297
+ "subscriptions",
298
+ "prices",
299
+ "products"
300
+ ];
301
+ function ensureStripeTables(db) {
302
+ db.pragma("busy_timeout = 5000");
303
+ db.pragma("journal_mode = WAL");
304
+ db.pragma("foreign_keys = ON");
305
+ db.exec(STRIPE_TABLES_SQL);
306
+ ensureMigratedColumns(db);
307
+ }
308
+ var MIGRATED_COLUMNS = {
309
+ payment_intents: [
310
+ ["payment_method_id", "payment_method_id TEXT"],
311
+ ["customer_id", "customer_id TEXT"],
312
+ ["last_payment_error_json", "last_payment_error_json TEXT"]
313
+ ],
314
+ charges: [
315
+ ["payment_method_id", "payment_method_id TEXT"],
316
+ ["payment_method_details_json", "payment_method_details_json TEXT"],
317
+ ["failure_code", "failure_code TEXT"],
318
+ ["failure_decline_code", "failure_decline_code TEXT"],
319
+ ["failure_message", "failure_message TEXT"],
320
+ ["customer_id", "customer_id TEXT"]
321
+ ],
322
+ refunds: [["balance_transaction_id", "balance_transaction_id TEXT"]]
323
+ };
324
+ function ensureMigratedColumns(db) {
325
+ for (const [table, columns] of Object.entries(MIGRATED_COLUMNS)) {
326
+ const existing = new Set(db.prepare(`SELECT name FROM pragma_table_info(?)`).all(table).map((row) => row.name));
327
+ if (existing.size === 0)
328
+ continue;
329
+ for (const [column, ddl] of columns) {
330
+ if (!existing.has(column))
331
+ db.exec(`ALTER TABLE ${table} ADD COLUMN ${ddl};`);
332
+ }
333
+ }
334
+ }
335
+ function resetStripeTables(db) {
336
+ for (const table of STRIPE_TABLES) {
337
+ db.exec(`DELETE FROM ${table};`);
338
+ }
339
+ }
340
+
341
+ // ../packages/twin-stripe/dist/src/seed.js
342
+ var DEFAULT_SID = "default";
343
+ var DEFAULT_API_KEY = "sk_test_pome_default";
344
+ var PI_STATUSES = [
345
+ "requires_payment_method",
346
+ "requires_confirmation",
347
+ "requires_action",
348
+ "processing",
349
+ "requires_capture",
350
+ "canceled",
351
+ "succeeded"
352
+ ];
353
+ var CHARGE_STATUSES = ["pending", "succeeded", "failed"];
354
+ var REFUND_STATUSES = ["succeeded", "pending", "failed", "canceled"];
355
+ var BALANCE_TX_STATUSES = ["pending", "available"];
356
+ var paymentIntentSeedSchema = z.object({
357
+ id: z.string().min(1),
358
+ account_id: z.string().min(1),
359
+ amount: z.number().int(),
360
+ currency: z.string().min(1),
361
+ status: z.enum(PI_STATUSES),
362
+ payment_method_types: z.array(z.string()).default(["crypto"]),
363
+ next_action: z.unknown().nullable().optional(),
364
+ latest_charge_id: z.string().nullable().optional(),
365
+ capture_method: z.string().default("automatic"),
366
+ confirmation_method: z.string().default("automatic"),
367
+ idempotency_key: z.string().nullable().optional(),
368
+ metadata: z.record(z.string(), z.string()).default({}),
369
+ crypto_deposit: z.unknown().nullable().optional(),
370
+ client_secret: z.string().min(1),
371
+ created: z.number().int(),
372
+ updated: z.number().int(),
373
+ canceled_at: z.number().int().nullable().optional(),
374
+ captured_at: z.number().int().nullable().optional()
375
+ });
376
+ var chargeSeedSchema = z.object({
377
+ id: z.string().min(1),
378
+ account_id: z.string().min(1),
379
+ payment_intent_id: z.string().min(1),
380
+ amount: z.number().int(),
381
+ amount_captured: z.number().int().default(0),
382
+ amount_refunded: z.number().int().default(0),
383
+ status: z.enum(CHARGE_STATUSES),
384
+ balance_transaction_id: z.string().nullable().optional(),
385
+ captured: z.boolean().default(true),
386
+ currency: z.string().min(1),
387
+ created: z.number().int()
388
+ });
389
+ var refundSeedSchema = z.object({
390
+ id: z.string().min(1),
391
+ account_id: z.string().min(1),
392
+ charge_id: z.string().min(1),
393
+ payment_intent_id: z.string().min(1),
394
+ amount: z.number().int(),
395
+ currency: z.string().min(1),
396
+ status: z.enum(REFUND_STATUSES),
397
+ reason: z.string().nullable().optional(),
398
+ balance_transaction_id: z.string().nullable().optional(),
399
+ idempotency_key: z.string().nullable().optional(),
400
+ created: z.number().int()
401
+ });
402
+ var balanceTransactionSeedSchema = z.object({
403
+ id: z.string().min(1),
404
+ account_id: z.string().min(1),
405
+ type: z.string().min(1),
406
+ amount: z.number().int(),
407
+ fee: z.number().int().default(0),
408
+ net: z.number().int(),
409
+ currency: z.string().min(1),
410
+ source_id: z.string().nullable().optional(),
411
+ source_type: z.string().nullable().optional(),
412
+ available_on: z.number().int(),
413
+ status: z.enum(BALANCE_TX_STATUSES).default("available"),
414
+ created: z.number().int()
415
+ });
416
+ var seedSchema = z.object({
417
+ api_keys: z.array(z.object({
418
+ key: z.string().min(1),
419
+ sid: z.string().min(1),
420
+ account_id: z.string().min(1).optional()
421
+ })).default([]),
422
+ failure_injection: z.array(failureInjectionRuleSchema).default([]),
423
+ payment_intents: z.array(paymentIntentSeedSchema).default([]),
424
+ charges: z.array(chargeSeedSchema).default([]),
425
+ refunds: z.array(refundSeedSchema).default([]),
426
+ balance_transactions: z.array(balanceTransactionSeedSchema).default([])
427
+ });
428
+ function parseSeed(input) {
429
+ return seedSchema.parse(input);
430
+ }
431
+ function loadSeedFromEnv(env = process.env) {
432
+ const raw = env.POME_SEED_JSON;
433
+ if (raw === void 0 || raw === "") {
434
+ return defaultSeed();
435
+ }
436
+ let parsed;
437
+ try {
438
+ parsed = JSON.parse(raw);
439
+ } catch (err) {
440
+ throw new Error(`POME_SEED_JSON is not valid JSON: ${err.message}`);
441
+ }
442
+ const unwrapped = unwrapStripeSeed(parsed);
443
+ return parseSeed(unwrapped);
444
+ }
445
+ function unwrapStripeSeed(value) {
446
+ if (value && typeof value === "object" && !Array.isArray(value)) {
447
+ const stripeKey = value.stripe;
448
+ if (stripeKey && typeof stripeKey === "object" && !Array.isArray(stripeKey)) {
449
+ const inner = stripeKey.seed;
450
+ if (inner !== void 0) {
451
+ return inner;
452
+ }
453
+ }
454
+ }
455
+ return value;
456
+ }
457
+ function defaultSeed() {
458
+ return {
459
+ api_keys: [
460
+ { key: DEFAULT_API_KEY, sid: DEFAULT_SID, account_id: `acct_${DEFAULT_SID}` }
461
+ ],
462
+ failure_injection: [],
463
+ payment_intents: [],
464
+ charges: [],
465
+ refunds: [],
466
+ balance_transactions: []
467
+ };
468
+ }
469
+ function applySeed(db, seed, failureInjection) {
470
+ ensureStripeTables(db);
471
+ for (const entry of seed.api_keys ?? []) {
472
+ mintApiKey(db, {
473
+ sid: entry.sid,
474
+ account_id: entry.account_id,
475
+ key: entry.key
476
+ });
477
+ }
478
+ for (const row of seed.payment_intents ?? []) {
479
+ insertSeedPaymentIntent(db, row);
480
+ }
481
+ for (const row of seed.charges ?? []) {
482
+ insertSeedCharge(db, row);
483
+ }
484
+ for (const row of seed.balance_transactions ?? []) {
485
+ insertSeedBalanceTransaction(db, row);
486
+ }
487
+ for (const row of seed.refunds ?? []) {
488
+ insertSeedRefund(db, row);
489
+ }
490
+ if (failureInjection) {
491
+ failureInjection.setRules(seed.failure_injection ?? []);
492
+ }
493
+ }
494
+ function insertSeedPaymentIntent(db, row) {
495
+ db.prepare(`INSERT INTO payment_intents (
496
+ id, account_id, amount, currency, status,
497
+ payment_method_types_json, next_action_json,
498
+ latest_charge_id, capture_method, confirmation_method,
499
+ idempotency_key, metadata_json, crypto_deposit_json,
500
+ client_secret, created, updated, canceled_at, captured_at
501
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(row.id, row.account_id, row.amount, row.currency, row.status, JSON.stringify(row.payment_method_types), row.next_action === void 0 || row.next_action === null ? null : JSON.stringify(row.next_action), row.latest_charge_id ?? null, row.capture_method, row.confirmation_method, row.idempotency_key ?? null, JSON.stringify(row.metadata), row.crypto_deposit === void 0 || row.crypto_deposit === null ? null : JSON.stringify(row.crypto_deposit), row.client_secret, row.created, row.updated, row.canceled_at ?? null, row.captured_at ?? null);
502
+ }
503
+ function insertSeedCharge(db, row) {
504
+ db.prepare(`INSERT INTO charges (
505
+ id, account_id, payment_intent_id, amount, amount_captured, amount_refunded,
506
+ status, balance_transaction_id, captured, currency, created
507
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(row.id, row.account_id, row.payment_intent_id, row.amount, row.amount_captured, row.amount_refunded, row.status, row.balance_transaction_id ?? null, row.captured ? 1 : 0, row.currency, row.created);
508
+ }
509
+ function insertSeedRefund(db, row) {
510
+ db.prepare(`INSERT INTO refunds (
511
+ id, account_id, charge_id, payment_intent_id, amount, currency,
512
+ status, reason, balance_transaction_id, idempotency_key, created
513
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(row.id, row.account_id, row.charge_id, row.payment_intent_id, row.amount, row.currency, row.status, row.reason ?? null, row.balance_transaction_id ?? null, row.idempotency_key ?? null, row.created);
514
+ }
515
+ function insertSeedBalanceTransaction(db, row) {
516
+ db.prepare(`INSERT INTO balance_transactions (
517
+ id, account_id, type, amount, fee, net, currency, source_id, source_type,
518
+ available_on, status, created
519
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(row.id, row.account_id, row.type, row.amount, row.fee, row.net, row.currency, row.source_id ?? null, row.source_type ?? null, row.available_on, row.status, row.created);
520
+ }
521
+
522
+ export { DEFAULT_API_KEY, DEFAULT_SID, applySeed, defaultSeed, ensureMigratedColumns, ensureStripeTables, loadSeedFromEnv, looksLikeApiKey, mintApiKey, newClientSecret, newId, nowIso, nowUnix, parseSeed, requestId, resetStripeTables, resolveSidFromKey, revokeApiKey, seedSchema };
@@ -0,0 +1,141 @@
1
+ import { z } from 'zod';
2
+
3
+ // ../packages/twin-slack/dist/src/seed.js
4
+ var seedSchema = z.object({
5
+ team: z.object({
6
+ id: z.string().regex(/^T[A-Z0-9_]+$/).optional(),
7
+ name: z.string().default("Pome Twin Workspace"),
8
+ domain: z.string().default("pome-twin")
9
+ }).prefault({}),
10
+ users: z.array(z.object({
11
+ id: z.string().regex(/^[UB][A-Z0-9_]+$/).optional(),
12
+ name: z.string().min(1),
13
+ real_name: z.string().default(""),
14
+ email: z.string().email().optional(),
15
+ is_bot: z.boolean().default(false),
16
+ is_admin: z.boolean().default(false),
17
+ tz: z.string().default("America/Los_Angeles"),
18
+ profile: z.record(z.string(), z.unknown()).default({})
19
+ })).default([]),
20
+ channels: z.array(z.object({
21
+ id: z.string().regex(/^[CGDM][A-Z0-9_]+$/).optional(),
22
+ name: z.string().regex(/^[a-z0-9_-]{1,80}$/),
23
+ is_private: z.boolean().default(false),
24
+ topic: z.string().default(""),
25
+ purpose: z.string().default(""),
26
+ creator: z.string().optional(),
27
+ members: z.array(z.string()).default([]),
28
+ messages: z.array(z.object({
29
+ ts: z.string().optional(),
30
+ user: z.string(),
31
+ text: z.string(),
32
+ thread_ts: z.string().optional(),
33
+ reactions: z.array(z.object({ name: z.string(), user: z.string() })).default([])
34
+ })).default([])
35
+ })).default([]),
36
+ // Files present in the world before the agent runs. `user` and
37
+ // `channels` are seed HANDLES (a user/channel `name`) or ids — the same
38
+ // currency `channels[].members` and `channels[].messages[].user` already use.
39
+ files: z.array(z.object({
40
+ id: z.string().regex(/^F[A-Z0-9_]+$/).optional(),
41
+ name: z.string().min(1),
42
+ title: z.string().optional(),
43
+ filetype: z.string().min(1).default("text"),
44
+ user: z.string().optional(),
45
+ channels: z.array(z.string()).default([]),
46
+ content: z.string().optional()
47
+ })).default([]),
48
+ emoji: z.array(z.object({
49
+ name: z.string().regex(/^[a-z0-9_+-]{1,100}$/),
50
+ url: z.string().url().optional(),
51
+ alias: z.string().regex(/^[a-z0-9_+-]{1,100}$/).optional()
52
+ })).default([])
53
+ });
54
+ function parseSeed(input) {
55
+ return seedSchema.parse(input);
56
+ }
57
+ function loadSeedFromEnv(env = process.env) {
58
+ const raw = env.POME_SEED_JSON;
59
+ if (raw === void 0 || raw === "") {
60
+ return defaultSeedState();
61
+ }
62
+ let parsed;
63
+ try {
64
+ parsed = JSON.parse(raw);
65
+ } catch (err) {
66
+ throw new Error(`POME_SEED_JSON is not valid JSON: ${err.message}`);
67
+ }
68
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
69
+ const obj = parsed;
70
+ if (obj.slack && typeof obj.slack === "object" && obj.slack !== null) {
71
+ const slack = obj.slack;
72
+ if ("seed" in slack) {
73
+ return parseSeed(slack.seed);
74
+ }
75
+ }
76
+ }
77
+ return parseSeed(parsed);
78
+ }
79
+ function defaultSeedState() {
80
+ return {
81
+ team: {
82
+ id: "T_POME",
83
+ name: "Pome Twin Workspace",
84
+ domain: "pome-twin"
85
+ },
86
+ users: [
87
+ {
88
+ id: "U_PRIMARY",
89
+ name: "pome-agent",
90
+ real_name: "Pome Agent",
91
+ email: "pome-agent@pome-twin.slack.com",
92
+ is_bot: false,
93
+ is_admin: true
94
+ },
95
+ {
96
+ id: "U_ALICE",
97
+ name: "alice",
98
+ real_name: "Alice",
99
+ email: "alice@pome-twin.slack.com"
100
+ },
101
+ {
102
+ id: "U_BOB",
103
+ name: "bob",
104
+ real_name: "Bob",
105
+ email: "bob@pome-twin.slack.com"
106
+ }
107
+ ],
108
+ channels: [
109
+ {
110
+ id: "C_GENERAL",
111
+ name: "general",
112
+ is_private: false,
113
+ topic: "Company-wide announcements and chatter.",
114
+ purpose: "This channel is for company-wide communication.",
115
+ creator: "U_PRIMARY",
116
+ members: ["U_PRIMARY", "U_ALICE", "U_BOB"],
117
+ messages: [
118
+ { user: "U_ALICE", text: "morning team" },
119
+ { user: "U_BOB", text: "morning :wave:" }
120
+ ]
121
+ },
122
+ {
123
+ id: "C_RANDOM",
124
+ name: "random",
125
+ is_private: false,
126
+ topic: "Non-work chatter and water cooler talk.",
127
+ purpose: "A place for non-work-related flimflam.",
128
+ creator: "U_PRIMARY",
129
+ members: [],
130
+ messages: []
131
+ }
132
+ ],
133
+ emoji: [
134
+ { name: "shipit", alias: "squirrel" },
135
+ { name: "squirrel" },
136
+ { name: "bowtie" }
137
+ ]
138
+ };
139
+ }
140
+
141
+ export { defaultSeedState, loadSeedFromEnv, parseSeed, seedSchema };
@@ -1,19 +1,20 @@
1
1
  import { newGroupId, reassuranceBox, twinReadyLine, trialsHeaderLine, trialLine, summaryLines, evaluatingLine, criterionPhrase } from './chunk-RGZBC7NF.js';
2
2
  import { DemoCapacityError, capacityLabel, parseCapacityMarker, capacityKindFrom } from './chunk-ZX4WNSZ5.js';
3
- import { runTask, demoTaskPath, DEMO_TASK_NAME, DEMO_REPO } from './chunk-FQGR7KDT.js';
4
- import { getAvailablePort } from './chunk-XDU6TD4O.js';
5
- import './chunk-CBFKZZBR.js';
6
- import { createHostedClient, parseTaskFile, uploadRunBlobs, scoreFromFinalizeResponse, scoreStatus, outcomeOf } from './chunk-ANKO3RCB.js';
3
+ import { runTask, demoTaskPath, DEMO_TASK_NAME, DEMO_REPO } from './chunk-N74LP4QH.js';
4
+ import { createHostedClient, parseTaskFile, uploadRunBlobs, scoreFromFinalizeResponse, scoreStatus, outcomeOf } from './chunk-CTA54N4K.js';
7
5
  import './chunk-NW7HGA2K.js';
6
+ import './chunk-3T5XN64P.js';
7
+ import './chunk-G6GOCYIT.js';
8
+ import { bootTwin } from './chunk-IK2F7ZA3.js';
9
+ import './chunk-JE4H5ODK.js';
10
+ import { getAvailablePort } from './chunk-XDU6TD4O.js';
8
11
  import { HostedQuotaError, HostedOrchError } from './chunk-BZO3YCJS.js';
9
- import './chunk-QXQAVKTE.js';
10
- import './chunk-NJ246QPJ.js';
11
- import './chunk-IZIZC7ZW.js';
12
- import { bootTwin } from './chunk-KIXYRPVY.js';
13
- import './chunk-EIUCTFQV.js';
14
- import './chunk-CFXEETE3.js';
12
+ import './chunk-CBFKZZBR.js';
13
+ import './chunk-HJX25USP.js';
14
+ import './chunk-E665XWYU.js';
15
15
  import './chunk-6KJC4BTO.js';
16
16
  import './chunk-SG6ZTIMT.js';
17
+ import './chunk-CF6EIU2U.js';
17
18
  import { readFile } from 'node:fs/promises';
18
19
  import { join } from 'node:path';
19
20
  import { z } from 'zod';