archal 0.9.17 → 0.9.19

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.
@@ -2981,7 +2981,7 @@ var require_compile = __commonJS({
2981
2981
  const schOrFunc = root.refs[ref2];
2982
2982
  if (schOrFunc)
2983
2983
  return schOrFunc;
2984
- let _sch = resolve5.call(this, root, ref2);
2984
+ let _sch = resolve6.call(this, root, ref2);
2985
2985
  if (_sch === void 0) {
2986
2986
  const schema = (_a2 = root.localRefs) === null || _a2 === void 0 ? void 0 : _a2[ref2];
2987
2987
  const { schemaId } = this.opts;
@@ -3008,7 +3008,7 @@ var require_compile = __commonJS({
3008
3008
  function sameSchemaEnv(s1, s2) {
3009
3009
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
3010
3010
  }
3011
- function resolve5(root, ref2) {
3011
+ function resolve6(root, ref2) {
3012
3012
  let sch;
3013
3013
  while (typeof (sch = this.refs[ref2]) == "string")
3014
3014
  ref2 = sch;
@@ -3583,55 +3583,55 @@ var require_fast_uri = __commonJS({
3583
3583
  }
3584
3584
  return uri;
3585
3585
  }
3586
- function resolve5(baseURI, relativeURI, options) {
3586
+ function resolve6(baseURI, relativeURI, options) {
3587
3587
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
3588
3588
  const resolved = resolveComponent(parse6(baseURI, schemelessOptions), parse6(relativeURI, schemelessOptions), schemelessOptions, true);
3589
3589
  schemelessOptions.skipEscape = true;
3590
3590
  return serialize(resolved, schemelessOptions);
3591
3591
  }
3592
- function resolveComponent(base, relative2, options, skipNormalization) {
3592
+ function resolveComponent(base, relative3, options, skipNormalization) {
3593
3593
  const target = {};
3594
3594
  if (!skipNormalization) {
3595
3595
  base = parse6(serialize(base, options), options);
3596
- relative2 = parse6(serialize(relative2, options), options);
3596
+ relative3 = parse6(serialize(relative3, options), options);
3597
3597
  }
3598
3598
  options = options || {};
3599
- if (!options.tolerant && relative2.scheme) {
3600
- target.scheme = relative2.scheme;
3601
- target.userinfo = relative2.userinfo;
3602
- target.host = relative2.host;
3603
- target.port = relative2.port;
3604
- target.path = removeDotSegments(relative2.path || "");
3605
- target.query = relative2.query;
3599
+ if (!options.tolerant && relative3.scheme) {
3600
+ target.scheme = relative3.scheme;
3601
+ target.userinfo = relative3.userinfo;
3602
+ target.host = relative3.host;
3603
+ target.port = relative3.port;
3604
+ target.path = removeDotSegments(relative3.path || "");
3605
+ target.query = relative3.query;
3606
3606
  } else {
3607
- if (relative2.userinfo !== void 0 || relative2.host !== void 0 || relative2.port !== void 0) {
3608
- target.userinfo = relative2.userinfo;
3609
- target.host = relative2.host;
3610
- target.port = relative2.port;
3611
- target.path = removeDotSegments(relative2.path || "");
3612
- target.query = relative2.query;
3607
+ if (relative3.userinfo !== void 0 || relative3.host !== void 0 || relative3.port !== void 0) {
3608
+ target.userinfo = relative3.userinfo;
3609
+ target.host = relative3.host;
3610
+ target.port = relative3.port;
3611
+ target.path = removeDotSegments(relative3.path || "");
3612
+ target.query = relative3.query;
3613
3613
  } else {
3614
- if (!relative2.path) {
3614
+ if (!relative3.path) {
3615
3615
  target.path = base.path;
3616
- if (relative2.query !== void 0) {
3617
- target.query = relative2.query;
3616
+ if (relative3.query !== void 0) {
3617
+ target.query = relative3.query;
3618
3618
  } else {
3619
3619
  target.query = base.query;
3620
3620
  }
3621
3621
  } else {
3622
- if (relative2.path[0] === "/") {
3623
- target.path = removeDotSegments(relative2.path);
3622
+ if (relative3.path[0] === "/") {
3623
+ target.path = removeDotSegments(relative3.path);
3624
3624
  } else {
3625
3625
  if ((base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0) && !base.path) {
3626
- target.path = "/" + relative2.path;
3626
+ target.path = "/" + relative3.path;
3627
3627
  } else if (!base.path) {
3628
- target.path = relative2.path;
3628
+ target.path = relative3.path;
3629
3629
  } else {
3630
- target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative2.path;
3630
+ target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative3.path;
3631
3631
  }
3632
3632
  target.path = removeDotSegments(target.path);
3633
3633
  }
3634
- target.query = relative2.query;
3634
+ target.query = relative3.query;
3635
3635
  }
3636
3636
  target.userinfo = base.userinfo;
3637
3637
  target.host = base.host;
@@ -3639,7 +3639,7 @@ var require_fast_uri = __commonJS({
3639
3639
  }
3640
3640
  target.scheme = base.scheme;
3641
3641
  }
3642
- target.fragment = relative2.fragment;
3642
+ target.fragment = relative3.fragment;
3643
3643
  return target;
3644
3644
  }
3645
3645
  function equal(uriA, uriB, options) {
@@ -3810,7 +3810,7 @@ var require_fast_uri = __commonJS({
3810
3810
  var fastUri = {
3811
3811
  SCHEMES,
3812
3812
  normalize,
3813
- resolve: resolve5,
3813
+ resolve: resolve6,
3814
3814
  resolveComponent,
3815
3815
  equal,
3816
3816
  serialize,
@@ -6809,7 +6809,7 @@ __export(dynamic_generator_exports, {
6809
6809
  module.exports = __toCommonJS(dynamic_generator_exports);
6810
6810
 
6811
6811
  // ../packages/seedgen/src/runner/seed/dynamic-generator.ts
6812
- var import_node_crypto14 = require("crypto");
6812
+ var import_node_crypto15 = require("crypto");
6813
6813
 
6814
6814
  // ../packages/node-auth/src/constants.ts
6815
6815
  var CREDENTIALS_FILE = "credentials.json";
@@ -7383,15 +7383,26 @@ var GENERATED_TWIN_CATALOG = [
7383
7383
  name: "Apify",
7384
7384
  description: "Actors, runs, datasets, key-value stores, and request queues.",
7385
7385
  toolCount: 43,
7386
- transport: "rest"
7386
+ transport: "rest",
7387
+ opsCoverage: null
7387
7388
  },
7388
7389
  {
7389
7390
  id: "discord",
7390
7391
  icon: "DC",
7391
7392
  name: "Discord",
7392
7393
  description: "Guilds, channels, messages, webhooks, threads, commands, and interaction responses.",
7393
- toolCount: 68,
7394
- transport: "both"
7394
+ toolCount: 67,
7395
+ transport: "both",
7396
+ opsCoverage: 14
7397
+ },
7398
+ {
7399
+ id: "firecrawl",
7400
+ icon: "FC",
7401
+ name: "Firecrawl",
7402
+ description: "Scraping, crawling, mapping, search, and extraction.",
7403
+ toolCount: 6,
7404
+ transport: "rest",
7405
+ opsCoverage: 77
7395
7406
  },
7396
7407
  {
7397
7408
  id: "github",
@@ -7399,15 +7410,26 @@ var GENERATED_TWIN_CATALOG = [
7399
7410
  name: "GitHub",
7400
7411
  description: "Repos, issues, pull requests, branches, and commits.",
7401
7412
  toolCount: 26,
7402
- transport: "both"
7413
+ transport: "both",
7414
+ opsCoverage: 96
7403
7415
  },
7404
7416
  {
7405
7417
  id: "google-workspace",
7406
7418
  icon: "GW",
7407
7419
  name: "Google Workspace",
7408
7420
  description: "Gmail, Calendar, Drive, Sheets, and Contacts.",
7409
- toolCount: 9,
7410
- transport: "both"
7421
+ toolCount: 249,
7422
+ transport: "both",
7423
+ opsCoverage: 64
7424
+ },
7425
+ {
7426
+ id: "hubspot",
7427
+ icon: "HS",
7428
+ name: "HubSpot",
7429
+ description: "CRM contacts, companies, deals, tickets, and engagements.",
7430
+ toolCount: 45,
7431
+ transport: "rest",
7432
+ opsCoverage: 10
7411
7433
  },
7412
7434
  {
7413
7435
  id: "jira",
@@ -7415,7 +7437,8 @@ var GENERATED_TWIN_CATALOG = [
7415
7437
  name: "Jira",
7416
7438
  description: "Issues, projects, boards, sprints, and versions.",
7417
7439
  toolCount: 49,
7418
- transport: "both"
7440
+ transport: "both",
7441
+ opsCoverage: 80
7419
7442
  },
7420
7443
  {
7421
7444
  id: "linear",
@@ -7423,7 +7446,8 @@ var GENERATED_TWIN_CATALOG = [
7423
7446
  name: "Linear",
7424
7447
  description: "Issues, projects, teams, cycles, and workflows.",
7425
7448
  toolCount: 42,
7426
- transport: "both"
7449
+ transport: "both",
7450
+ opsCoverage: 98
7427
7451
  },
7428
7452
  {
7429
7453
  id: "ramp",
@@ -7431,7 +7455,17 @@ var GENERATED_TWIN_CATALOG = [
7431
7455
  name: "Ramp",
7432
7456
  description: "Cards, funds, expenses, reimbursements, bills, and travel.",
7433
7457
  toolCount: 46,
7434
- transport: "mcp"
7458
+ transport: "mcp",
7459
+ opsCoverage: null
7460
+ },
7461
+ {
7462
+ id: "sendgrid",
7463
+ icon: "SG",
7464
+ name: "SendGrid",
7465
+ description: "Mail send, contacts, lists, templates, and stats.",
7466
+ toolCount: 28,
7467
+ transport: "rest",
7468
+ opsCoverage: 100
7435
7469
  },
7436
7470
  {
7437
7471
  id: "slack",
@@ -7439,7 +7473,8 @@ var GENERATED_TWIN_CATALOG = [
7439
7473
  name: "Slack",
7440
7474
  description: "Channels, messages, threads, users, and reactions.",
7441
7475
  toolCount: 8,
7442
- transport: "both"
7476
+ transport: "both",
7477
+ opsCoverage: 100
7443
7478
  },
7444
7479
  {
7445
7480
  id: "stripe",
@@ -7447,7 +7482,8 @@ var GENERATED_TWIN_CATALOG = [
7447
7482
  name: "Stripe",
7448
7483
  description: "Customers, payments, subscriptions, invoices, and refunds.",
7449
7484
  toolCount: 28,
7450
- transport: "both"
7485
+ transport: "both",
7486
+ opsCoverage: null
7451
7487
  },
7452
7488
  {
7453
7489
  id: "supabase",
@@ -7455,7 +7491,8 @@ var GENERATED_TWIN_CATALOG = [
7455
7491
  name: "Supabase",
7456
7492
  description: "SQL, migrations, logs, branches, and project metadata.",
7457
7493
  toolCount: 29,
7458
- transport: "both"
7494
+ transport: "both",
7495
+ opsCoverage: 100
7459
7496
  },
7460
7497
  {
7461
7498
  id: "tavily",
@@ -7463,7 +7500,35 @@ var GENERATED_TWIN_CATALOG = [
7463
7500
  name: "Tavily",
7464
7501
  description: "Search, extract, crawl, map, research, usage, and API key operations.",
7465
7502
  toolCount: 11,
7466
- transport: "rest"
7503
+ transport: "rest",
7504
+ opsCoverage: 100
7505
+ },
7506
+ {
7507
+ id: "telegram",
7508
+ icon: "TG",
7509
+ name: "Telegram",
7510
+ description: "Bot messages, chats, updates, and webhooks.",
7511
+ toolCount: 32,
7512
+ transport: "both",
7513
+ opsCoverage: null
7514
+ },
7515
+ {
7516
+ id: "twilio",
7517
+ icon: "TW",
7518
+ name: "Twilio",
7519
+ description: "Messages, calls, phone numbers, and verifications.",
7520
+ toolCount: 35,
7521
+ transport: "rest",
7522
+ opsCoverage: 92
7523
+ },
7524
+ {
7525
+ id: "unipile",
7526
+ icon: "UP",
7527
+ name: "Unipile",
7528
+ description: "LinkedIn and email messaging, accounts, and chats.",
7529
+ toolCount: 24,
7530
+ transport: "rest",
7531
+ opsCoverage: 100
7467
7532
  }
7468
7533
  ];
7469
7534
  var GENERATED_STARTABLE_TWIN_IDS = [
@@ -7566,6 +7631,51 @@ var LIFETIME_PERIOD_RESETS_AT = new Date(Date.UTC(9999, 11, 31));
7566
7631
  var SCENARIO_USAGE_WINDOW_DAYS = 7;
7567
7632
  var SCENARIO_USAGE_WINDOW_MS = SCENARIO_USAGE_WINDOW_DAYS * 24 * 60 * 60 * 1e3;
7568
7633
  var SCENARIO_USAGE_WINDOW_SECONDS = SCENARIO_USAGE_WINDOW_DAYS * 24 * 60 * 60;
7634
+ var LLM_PRICING_USD_PER_M_TOKENS = {
7635
+ // Google Gemini (verified 2026-05-05, standard tier <=200K input tokens)
7636
+ "gemini-2.5-pro": { input: 1.25, output: 10 },
7637
+ "gemini-2.5-flash": { input: 0.3, output: 2.5 },
7638
+ // OpenAI flagship text models (verified 2026-05-21, standard short-context tier)
7639
+ "gpt-5.5": { input: 5, output: 30 },
7640
+ "gpt-5.5-pro": { input: 30, output: 180 },
7641
+ "gpt-5.4": { input: 2.5, output: 15 },
7642
+ "gpt-5.4-mini": { input: 0.75, output: 4.5 },
7643
+ "gpt-5.4-nano": { input: 0.2, output: 1.25 },
7644
+ "gpt-5.4-pro": { input: 30, output: 180 },
7645
+ "gpt-4o-mini": { input: 0.15, output: 0.6 },
7646
+ "gpt-4o": { input: 2.5, output: 10 },
7647
+ "gpt-4.1-mini": { input: 0.4, output: 1.6 },
7648
+ "gpt-4.1-nano": { input: 0.1, output: 0.4 },
7649
+ "gpt-4.1": { input: 2, output: 8 },
7650
+ // DeepSeek (verified 2026-05-05; legacy names map to v4-flash per vendor)
7651
+ "deepseek-chat": { input: 0.14, output: 0.28 },
7652
+ "deepseek-reasoner": { input: 0.14, output: 0.28 },
7653
+ "deepseek-v4-flash": { input: 0.14, output: 0.28 }
7654
+ };
7655
+ var LLM_PRICING_FAMILY_RATES = [
7656
+ { match: /^gemini-2\.5-pro/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gemini-2.5-pro"] },
7657
+ { match: /^gemini-2\.5-flash/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gemini-2.5-flash"] },
7658
+ { match: /^gpt-5\.5-pro/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gpt-5.5-pro"] },
7659
+ { match: /^gpt-5\.5/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gpt-5.5"] },
7660
+ { match: /^gpt-5\.4-pro/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gpt-5.4-pro"] },
7661
+ { match: /^gpt-5\.4-mini/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gpt-5.4-mini"] },
7662
+ { match: /^gpt-5\.4-nano/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gpt-5.4-nano"] },
7663
+ { match: /^gpt-5\.4/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gpt-5.4"] },
7664
+ { match: /^gpt-4o-mini/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gpt-4o-mini"] },
7665
+ { match: /^gpt-4o(?!-mini)/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gpt-4o"] },
7666
+ { match: /^gpt-4\.1-mini/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gpt-4.1-mini"] },
7667
+ { match: /^gpt-4\.1-nano/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gpt-4.1-nano"] },
7668
+ { match: /^gpt-4\.1(?!-mini|-nano)/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gpt-4.1"] },
7669
+ { match: /^claude-opus-/i, rate: { input: 15, output: 75 } },
7670
+ { match: /^claude-haiku-/i, rate: { input: 0.8, output: 4 } },
7671
+ { match: /^claude-sonnet-/i, rate: { input: 3, output: 15 } },
7672
+ { match: /^opus-/i, rate: { input: 15, output: 75 } },
7673
+ { match: /^haiku-/i, rate: { input: 0.8, output: 4 } },
7674
+ { match: /^sonnet-/i, rate: { input: 3, output: 15 } },
7675
+ { match: /^deepseek-chat/i, rate: LLM_PRICING_USD_PER_M_TOKENS["deepseek-chat"] },
7676
+ { match: /^deepseek-reasoner/i, rate: LLM_PRICING_USD_PER_M_TOKENS["deepseek-reasoner"] },
7677
+ { match: /^deepseek-v4-flash/i, rate: LLM_PRICING_USD_PER_M_TOKENS["deepseek-v4-flash"] }
7678
+ ];
7569
7679
 
7570
7680
  // ../twins/core/src/errors.ts
7571
7681
  function errorMessage2(error48) {
@@ -26979,14 +27089,84 @@ var import_node_crypto7 = require("crypto");
26979
27089
  var import_node_perf_hooks = require("perf_hooks");
26980
27090
 
26981
27091
  // ../twins/core/src/fixture-oracle.ts
26982
- var import_node_fs4 = require("fs");
26983
- var import_node_path3 = require("path");
27092
+ var import_node_fs6 = require("fs");
27093
+ var import_node_path5 = require("path");
26984
27094
  var import_node_url2 = require("url");
26985
27095
 
26986
- // ../twins/core/src/run-twin-cli.ts
27096
+ // ../twins/core/src/legacy-asset-cache.ts
27097
+ var import_node_crypto9 = require("crypto");
26987
27098
  var import_node_fs5 = require("fs");
27099
+ var import_node_os3 = require("os");
26988
27100
  var import_node_path4 = require("path");
26989
27101
 
27102
+ // ../twins/core/src/recording-fetcher.ts
27103
+ var import_node_crypto8 = require("crypto");
27104
+ var import_node_fs4 = require("fs");
27105
+ var import_node_os2 = require("os");
27106
+ var import_node_path3 = require("path");
27107
+ var RecordingManifestEntrySchema = external_exports3.object({
27108
+ filename: external_exports3.string(),
27109
+ sha256: external_exports3.string().regex(/^[0-9a-f]{64}$/, "sha256 must be 64 lowercase hex chars"),
27110
+ size: external_exports3.number().optional(),
27111
+ sizeBytes: external_exports3.number().optional(),
27112
+ uploadedAt: external_exports3.string().optional(),
27113
+ // Optional symbolic tags that map fixture-oracle / replay lookups onto this
27114
+ // recording. Lets twins keep tag→file resolution inside the manifest itself
27115
+ // rather than depending on a separate provenance.json (which is excluded
27116
+ // from the in-tree fixture allowlist for graduated twins). Codex P2 on
27117
+ // tavily #3603 — fixture-oracle previously required provenance.json to
27118
+ // resolve `rest-profile:tavily:tavily_search_basic` → filename.
27119
+ tags: external_exports3.array(external_exports3.string()).optional()
27120
+ }).loose();
27121
+ var RecordingManifestSchema = external_exports3.object({
27122
+ service: external_exports3.string().min(1),
27123
+ version: external_exports3.number().int(),
27124
+ container: external_exports3.string().min(1),
27125
+ baseUrl: external_exports3.string().optional(),
27126
+ entries: external_exports3.array(RecordingManifestEntrySchema)
27127
+ }).loose();
27128
+ var DEFAULT_BASE_URL = process.env["ARCHAL_FIXTURE_BASE_URL"] ?? "https://archalforge8f96908966.blob.core.windows.net/archal-fixture-artifacts?sv=2023-11-03&spr=https&se=2031-05-10T00%3A00%3A00Z&sr=c&sp=rl&sig=r3%2FC3EwzilSHls8z3Pn5ZR%2BkinwQw1C6%2BDKObIZSIu0%3D";
27129
+ var DEFAULT_CACHE_ROOT = process.env["ARCHAL_FIXTURE_CACHE_ROOT"] ?? (0, import_node_path3.resolve)((0, import_node_os2.homedir)(), ".archal", "forge", "recordings-cache");
27130
+ function warnIfSasExpiresSoon(baseUrl) {
27131
+ if (process.env["ARCHAL_FIXTURE_SAS_WARN"] === "0") return;
27132
+ const queryIdx = baseUrl.indexOf("?");
27133
+ if (queryIdx < 0) return;
27134
+ const query = baseUrl.slice(queryIdx + 1);
27135
+ const seParam = query.split("&").find((p) => p.startsWith("se="));
27136
+ if (!seParam) return;
27137
+ const seValue = decodeURIComponent(seParam.slice(3));
27138
+ const expiresAt = Date.parse(seValue);
27139
+ if (Number.isNaN(expiresAt)) return;
27140
+ const now = Date.now();
27141
+ const daysRemaining = Math.floor((expiresAt - now) / (1e3 * 60 * 60 * 24));
27142
+ if (daysRemaining < 365) {
27143
+ console.warn(
27144
+ `[recording-fetcher] SAS token in ARCHAL_FIXTURE_BASE_URL expires in ${daysRemaining}d (${seValue}). Rotate via scripts/rotate-fixture-sas.mjs before expiry.`
27145
+ );
27146
+ }
27147
+ }
27148
+ warnIfSasExpiresSoon(DEFAULT_BASE_URL);
27149
+
27150
+ // ../twins/core/src/legacy-asset-cache.ts
27151
+ var DEFAULT_CACHE_ROOT2 = process.env["ARCHAL_LEGACY_ASSET_CACHE_ROOT"] ?? (0, import_node_path4.resolve)((0, import_node_os3.homedir)(), ".archal", "forge", "legacy-assets-cache");
27152
+ var LegacyAssetEntrySchema = external_exports3.object({
27153
+ relativePath: external_exports3.string().min(1),
27154
+ sha256: external_exports3.string().regex(/^[0-9a-f]{64}$/, "sha256 must be 64 lowercase hex chars"),
27155
+ sizeBytes: external_exports3.number().optional(),
27156
+ uploadedAt: external_exports3.string().optional()
27157
+ }).loose();
27158
+ var LegacyAssetManifestSchema = external_exports3.object({
27159
+ service: external_exports3.string().min(1),
27160
+ version: external_exports3.number().int(),
27161
+ container: external_exports3.string().min(1),
27162
+ layout: external_exports3.string().optional(),
27163
+ entries: external_exports3.array(LegacyAssetEntrySchema)
27164
+ }).loose();
27165
+
27166
+ // ../twins/core/src/run-twin-cli.ts
27167
+ var import_node_fs7 = require("fs");
27168
+ var import_node_path6 = require("path");
27169
+
26990
27170
  // ../twins/manifest.json
26991
27171
  var manifest_default = [
26992
27172
  {
@@ -27036,6 +27216,12 @@ var manifest_default = [
27036
27216
  package: "@archal/twin-firecrawl",
27037
27217
  path: "twins/firecrawl",
27038
27218
  stage: "internal",
27219
+ display: {
27220
+ icon: "FC",
27221
+ name: "Firecrawl",
27222
+ description: "Scraping, crawling, mapping, search, and extraction.",
27223
+ toolCount: 6
27224
+ },
27039
27225
  transport: "rest",
27040
27226
  hostedRuntime: { enabled: true, requiresDist: true, requiresEmptySeed: true },
27041
27227
  cli: { bundleAssets: false, bundleToolSnapshot: false },
@@ -27103,6 +27289,12 @@ var manifest_default = [
27103
27289
  package: "@archal/twin-hubspot",
27104
27290
  path: "twins/hubspot",
27105
27291
  stage: "internal",
27292
+ display: {
27293
+ icon: "HS",
27294
+ name: "HubSpot",
27295
+ description: "CRM contacts, companies, deals, tickets, and engagements.",
27296
+ toolCount: 45
27297
+ },
27106
27298
  transport: "rest",
27107
27299
  hostedRuntime: { enabled: true, requiresDist: true, requiresEmptySeed: true },
27108
27300
  cli: { bundleAssets: false, bundleToolSnapshot: false },
@@ -27179,6 +27371,12 @@ var manifest_default = [
27179
27371
  package: "@archal/twin-sendgrid",
27180
27372
  path: "twins/sendgrid",
27181
27373
  stage: "internal",
27374
+ display: {
27375
+ icon: "SG",
27376
+ name: "SendGrid",
27377
+ description: "Mail send, contacts, lists, templates, and stats.",
27378
+ toolCount: 28
27379
+ },
27182
27380
  transport: "rest",
27183
27381
  hostedRuntime: { enabled: true, requiresDist: true, requiresEmptySeed: true },
27184
27382
  cli: { bundleAssets: false, bundleToolSnapshot: false },
@@ -27275,6 +27473,12 @@ var manifest_default = [
27275
27473
  package: "@archal/twin-telegram",
27276
27474
  path: "twins/telegram",
27277
27475
  stage: "internal",
27476
+ display: {
27477
+ icon: "TG",
27478
+ name: "Telegram",
27479
+ description: "Bot messages, chats, updates, and webhooks.",
27480
+ toolCount: 32
27481
+ },
27278
27482
  transport: "both",
27279
27483
  hostedRuntime: { enabled: true, requiresDist: true, requiresEmptySeed: true },
27280
27484
  cli: { bundleAssets: false, bundleToolSnapshot: false },
@@ -27287,6 +27491,12 @@ var manifest_default = [
27287
27491
  package: "@archal/twin-twilio",
27288
27492
  path: "twins/twilio",
27289
27493
  stage: "internal",
27494
+ display: {
27495
+ icon: "TW",
27496
+ name: "Twilio",
27497
+ description: "Messages, calls, phone numbers, and verifications.",
27498
+ toolCount: 35
27499
+ },
27290
27500
  transport: "rest",
27291
27501
  hostedRuntime: { enabled: true, requiresDist: true, requiresEmptySeed: true },
27292
27502
  cli: { bundleAssets: false, bundleToolSnapshot: false },
@@ -27299,6 +27509,12 @@ var manifest_default = [
27299
27509
  package: "@archal/twin-unipile",
27300
27510
  path: "twins/unipile",
27301
27511
  stage: "internal",
27512
+ display: {
27513
+ icon: "UP",
27514
+ name: "Unipile",
27515
+ description: "LinkedIn and email messaging, accounts, and chats.",
27516
+ toolCount: 24
27517
+ },
27302
27518
  transport: "rest",
27303
27519
  hostedRuntime: { enabled: true, requiresDist: true, requiresEmptySeed: true },
27304
27520
  cli: { bundleAssets: false, bundleToolSnapshot: false },
@@ -27317,10 +27533,10 @@ var CLONE_PACKAGES = CLONE_MANIFEST.map((t) => t.package);
27317
27533
  var TWIN_PREFIX_PATTERN = new RegExp(`^(${CLONE_NAMES.join("|")})_`, "i");
27318
27534
 
27319
27535
  // ../twins/core/src/session-run-id.ts
27320
- var import_node_crypto8 = require("crypto");
27536
+ var import_node_crypto10 = require("crypto");
27321
27537
 
27322
27538
  // ../twins/core/src/webhook-signing.ts
27323
- var import_node_crypto9 = require("crypto");
27539
+ var import_node_crypto11 = require("crypto");
27324
27540
 
27325
27541
  // ../twins/core/src/scenario-schemas.ts
27326
27542
  var successCriterionSchema = external_exports3.object({
@@ -27458,59 +27674,11 @@ var SCENARIO_RISK_TAXONOMY = SCENARIO_RISK_RULES.map(
27458
27674
  ({ id, label, description }) => ({ id, label, description })
27459
27675
  );
27460
27676
 
27461
- // ../twins/core/src/recording-fetcher.ts
27462
- var import_node_crypto10 = require("crypto");
27463
- var import_node_fs6 = require("fs");
27464
- var import_node_os2 = require("os");
27465
- var import_node_path5 = require("path");
27466
- var RecordingManifestEntrySchema = external_exports3.object({
27467
- filename: external_exports3.string(),
27468
- sha256: external_exports3.string().regex(/^[0-9a-f]{64}$/, "sha256 must be 64 lowercase hex chars"),
27469
- size: external_exports3.number().optional(),
27470
- sizeBytes: external_exports3.number().optional(),
27471
- uploadedAt: external_exports3.string().optional(),
27472
- // Optional symbolic tags that map fixture-oracle / replay lookups onto this
27473
- // recording. Lets twins keep tag→file resolution inside the manifest itself
27474
- // rather than depending on a separate provenance.json (which is excluded
27475
- // from the in-tree fixture allowlist for graduated twins). Codex P2 on
27476
- // tavily #3603 — fixture-oracle previously required provenance.json to
27477
- // resolve `rest-profile:tavily:tavily_search_basic` → filename.
27478
- tags: external_exports3.array(external_exports3.string()).optional()
27479
- }).loose();
27480
- var RecordingManifestSchema = external_exports3.object({
27481
- service: external_exports3.string().min(1),
27482
- version: external_exports3.number().int(),
27483
- container: external_exports3.string().min(1),
27484
- baseUrl: external_exports3.string().optional(),
27485
- entries: external_exports3.array(RecordingManifestEntrySchema)
27486
- }).loose();
27487
- var DEFAULT_BASE_URL = process.env["ARCHAL_FIXTURE_BASE_URL"] ?? "https://archalforge8f96908966.blob.core.windows.net/archal-fixture-artifacts?sv=2023-11-03&spr=https&se=2031-05-10T00%3A00%3A00Z&sr=c&sp=rl&sig=r3%2FC3EwzilSHls8z3Pn5ZR%2BkinwQw1C6%2BDKObIZSIu0%3D";
27488
- var DEFAULT_CACHE_ROOT = process.env["ARCHAL_FIXTURE_CACHE_ROOT"] ?? (0, import_node_path5.resolve)((0, import_node_os2.homedir)(), ".archal", "forge", "recordings-cache");
27489
- function warnIfSasExpiresSoon(baseUrl) {
27490
- if (process.env["ARCHAL_FIXTURE_SAS_WARN"] === "0") return;
27491
- const queryIdx = baseUrl.indexOf("?");
27492
- if (queryIdx < 0) return;
27493
- const query = baseUrl.slice(queryIdx + 1);
27494
- const seParam = query.split("&").find((p) => p.startsWith("se="));
27495
- if (!seParam) return;
27496
- const seValue = decodeURIComponent(seParam.slice(3));
27497
- const expiresAt = Date.parse(seValue);
27498
- if (Number.isNaN(expiresAt)) return;
27499
- const now = Date.now();
27500
- const daysRemaining = Math.floor((expiresAt - now) / (1e3 * 60 * 60 * 24));
27501
- if (daysRemaining < 365) {
27502
- console.warn(
27503
- `[recording-fetcher] SAS token in ARCHAL_FIXTURE_BASE_URL expires in ${daysRemaining}d (${seValue}). Rotate via scripts/rotate-fixture-sas.mjs before expiry.`
27504
- );
27505
- }
27506
- }
27507
- warnIfSasExpiresSoon(DEFAULT_BASE_URL);
27508
-
27509
27677
  // ../packages/seedgen/src/codegen/executor.ts
27510
27678
  var import_node_child_process2 = require("child_process");
27511
- var import_node_fs7 = require("fs");
27679
+ var import_node_fs8 = require("fs");
27512
27680
  var import_node_url3 = require("url");
27513
- var import_node_path6 = __toESM(require("path"), 1);
27681
+ var import_node_path7 = __toESM(require("path"), 1);
27514
27682
  var import_node_vm2 = __toESM(require("vm"), 1);
27515
27683
 
27516
27684
  // ../packages/seedgen/src/codegen/builder-ids.ts
@@ -34457,15 +34625,15 @@ var import_node_vm = __toESM(require("vm"), 1);
34457
34625
  var import_meta = {};
34458
34626
  var DEFAULT_TIMEOUT_MS = 5e3;
34459
34627
  function resolveWorkerScriptPath() {
34460
- const thisDir = import_node_path6.default.dirname((0, import_node_url3.fileURLToPath)(import_meta.url));
34628
+ const thisDir = import_node_path7.default.dirname((0, import_node_url3.fileURLToPath)(import_meta.url));
34461
34629
  const candidates = [
34462
34630
  // Source or unbundled output: executor.js and subprocess-worker.js live together.
34463
- import_node_path6.default.join(thisDir, "subprocess-worker.js"),
34631
+ import_node_path7.default.join(thisDir, "subprocess-worker.js"),
34464
34632
  // tsup bundles executor into a root chunk while keeping the worker entry
34465
34633
  // at dist/codegen/subprocess-worker.js.
34466
- import_node_path6.default.join(thisDir, "codegen", "subprocess-worker.js")
34634
+ import_node_path7.default.join(thisDir, "codegen", "subprocess-worker.js")
34467
34635
  ];
34468
- return candidates.find((candidate) => (0, import_node_fs7.existsSync)(candidate));
34636
+ return candidates.find((candidate) => (0, import_node_fs8.existsSync)(candidate));
34469
34637
  }
34470
34638
  var workerScriptPath;
34471
34639
  try {
@@ -34482,7 +34650,7 @@ async function executeSeedCodeIsolated(code, twinName, baseSeed, timeoutMs = DEF
34482
34650
  "seedgen: subprocess worker script is unresolvable. Ensure the package is built before use."
34483
34651
  );
34484
34652
  }
34485
- return new Promise((resolve5) => {
34653
+ return new Promise((resolve6) => {
34486
34654
  const child = (0, import_node_child_process2.fork)(workerScriptPath, {
34487
34655
  // Silent: don't inherit parent stdout/stderr so worker crashes
34488
34656
  // don't pollute the parent's output.
@@ -34507,28 +34675,28 @@ async function executeSeedCodeIsolated(code, twinName, baseSeed, timeoutMs = DEF
34507
34675
  if (!resolved) {
34508
34676
  resolved = true;
34509
34677
  child.kill("SIGKILL");
34510
- resolve5({ ok: false, type: "timeout", message: `Subprocess timed out after ${timeoutMs}ms` });
34678
+ resolve6({ ok: false, type: "timeout", message: `Subprocess timed out after ${timeoutMs}ms` });
34511
34679
  }
34512
34680
  }, timeoutMs + 2e3);
34513
34681
  child.on("message", (msg) => {
34514
34682
  if (!resolved) {
34515
34683
  resolved = true;
34516
34684
  clearTimeout(timer);
34517
- resolve5(msg);
34685
+ resolve6(msg);
34518
34686
  }
34519
34687
  });
34520
34688
  child.on("error", (err) => {
34521
34689
  if (!resolved) {
34522
34690
  resolved = true;
34523
34691
  clearTimeout(timer);
34524
- resolve5({ ok: false, type: "runtime", message: `Worker error: ${errorMessage2(err)}` });
34692
+ resolve6({ ok: false, type: "runtime", message: `Worker error: ${errorMessage2(err)}` });
34525
34693
  }
34526
34694
  });
34527
34695
  child.on("exit", (exitCode) => {
34528
34696
  if (!resolved) {
34529
34697
  resolved = true;
34530
34698
  clearTimeout(timer);
34531
- resolve5({
34699
+ resolve6({
34532
34700
  ok: false,
34533
34701
  type: "runtime",
34534
34702
  message: exitCode ? `Worker exited with code ${exitCode}` : "Worker exited unexpectedly"
@@ -35915,7 +36083,7 @@ function buildCodegenUserPrompt(twinName, setupDescription) {
35915
36083
  const declarations = SDK_DECLARATIONS[twinName];
35916
36084
  const example = SDK_EXAMPLES[twinName];
35917
36085
  if (!declarations) {
35918
- return `Twin: ${twinName}
36086
+ return `Clone: ${twinName}
35919
36087
 
35920
36088
  Setup:
35921
36089
  ${setupDescription}
@@ -35936,7 +36104,7 @@ ${example.code}
35936
36104
  `;
35937
36105
  }
35938
36106
  prompt += `## Task
35939
- Twin: ${twinName}
36107
+ Clone: ${twinName}
35940
36108
 
35941
36109
  Setup:
35942
36110
  ${setupDescription}
@@ -35962,7 +36130,7 @@ ${originalCode}
35962
36130
  Fix the code and output ONLY the corrected JavaScript. No explanations.`;
35963
36131
  }
35964
36132
  function buildSimplifiedCodegenPrompt(twinName, setupDescription) {
35965
- return `Create seed data for the "${twinName}" twin.
36133
+ return `Create seed data for the "${twinName}" clone.
35966
36134
 
35967
36135
  Use ONLY these core functions (they are already defined globally):
35968
36136
  createUser(login), createRepo/createProject/createChannel/createCustomer(name),
@@ -36117,7 +36285,7 @@ var TRANSIENT_AWS_EXCEPTIONS_PATTERN = /ThrottlingException|ServiceUnavailableEx
36117
36285
  var STATUS_CODE_IN_MESSAGE_PATTERN = /\b(429|500|502|503|529)\b/;
36118
36286
  var TRANSIENT_NETWORK_ERRORS_PATTERN = /ECONNRESET|ETIMEDOUT|EAI_AGAIN/i;
36119
36287
  function defaultSleep(backoffMs) {
36120
- return new Promise((resolve5) => setTimeout(resolve5, backoffMs));
36288
+ return new Promise((resolve6) => setTimeout(resolve6, backoffMs));
36121
36289
  }
36122
36290
  function getServerHintedDelayMs(error48) {
36123
36291
  if (error48 instanceof UpstreamApiError && typeof error48.retryAfterMs === "number" && error48.retryAfterMs >= 0) {
@@ -36724,7 +36892,7 @@ RULES:
36724
36892
  - "3 active subscriptions" \u2192 ONE subscription entry with count:3
36725
36893
  - Entity type names: user, org, team, repo, branch, issue, pr, label, milestone, release, webhook, workflow, environment, secret, code_scanning_alert, collaborator, project, page, branch_protection, board, sprint, epic, component, version, filter, dashboard, customer, product, price, subscription, invoice, payment_method, coupon, tax_rate, webhook_endpoint, charge, dispute, channel, message`;
36726
36894
  function buildPlanPrompt(twinName, setupDescription) {
36727
- return `Twin: ${twinName}
36895
+ return `Clone: ${twinName}
36728
36896
 
36729
36897
  Setup:
36730
36898
  ${setupDescription}`;
@@ -37446,7 +37614,7 @@ function progress(message) {
37446
37614
  }
37447
37615
 
37448
37616
  // ../packages/seedgen/src/runner/seed/fill-templates.ts
37449
- var import_node_crypto11 = require("crypto");
37617
+ var import_node_crypto12 = require("crypto");
37450
37618
  function firstOf(seed, key) {
37451
37619
  const arr = seed[key];
37452
37620
  if (Array.isArray(arr) && arr.length > 0) {
@@ -38029,7 +38197,7 @@ var stripeWebhookEndpoints = (i, name, _d, _seed, _fk) => ({
38029
38197
  url: `https://example.com/webhooks/stripe`,
38030
38198
  enabledEvents: ["payment_intent.succeeded", "invoice.payment_succeeded"],
38031
38199
  status: "enabled",
38032
- secret: `whsec_${(0, import_node_crypto11.randomBytes)(24).toString("hex")}`,
38200
+ secret: `whsec_${(0, import_node_crypto12.randomBytes)(24).toString("hex")}`,
38033
38201
  description: name || null,
38034
38202
  apiVersion: "2024-06-20",
38035
38203
  livemode: false
@@ -42334,10 +42502,10 @@ function extractSeedIntent(twinName, setupDescription) {
42334
42502
  }
42335
42503
 
42336
42504
  // ../packages/seedgen/src/runner/seed/cache.ts
42337
- var import_node_crypto12 = require("crypto");
42338
- var import_node_fs8 = require("fs");
42339
- var import_node_path7 = require("path");
42340
- var import_node_os3 = require("os");
42505
+ var import_node_crypto13 = require("crypto");
42506
+ var import_node_fs9 = require("fs");
42507
+ var import_node_path8 = require("path");
42508
+ var import_node_os4 = require("os");
42341
42509
 
42342
42510
  // ../packages/seedgen/src/evaluator/deterministic-state.ts
42343
42511
  function flattenTwinState(state) {
@@ -42702,13 +42870,13 @@ function trimSeedToExpectedCounts(seed, mismatches) {
42702
42870
 
42703
42871
  // ../packages/seedgen/src/runner/seed/cache.ts
42704
42872
  var SEED_CACHE_VERSION = 6;
42705
- var CACHE_DIR = (0, import_node_path7.join)((0, import_node_os3.homedir)(), ".archal", "seed-cache");
42873
+ var CACHE_DIR = (0, import_node_path8.join)((0, import_node_os4.homedir)(), ".archal", "seed-cache");
42706
42874
  var MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
42707
42875
  function normalizeSetupText(setupText) {
42708
42876
  return setupText.toLowerCase().replace(/[^a-z0-9\s_/-]/g, " ").replace(/\s+/g, " ").trim();
42709
42877
  }
42710
42878
  function setupHash(normalizedSetup) {
42711
- return (0, import_node_crypto12.createHash)("sha256").update(normalizedSetup).digest("hex").slice(0, 32);
42879
+ return (0, import_node_crypto13.createHash)("sha256").update(normalizedSetup).digest("hex").slice(0, 32);
42712
42880
  }
42713
42881
  function canonicalize(value) {
42714
42882
  if (Array.isArray(value)) {
@@ -42725,7 +42893,7 @@ function canonicalize(value) {
42725
42893
  return value;
42726
42894
  }
42727
42895
  function hashValue(value) {
42728
- return (0, import_node_crypto12.createHash)("sha256").update(JSON.stringify(canonicalize(value))).digest("hex").slice(0, 32);
42896
+ return (0, import_node_crypto13.createHash)("sha256").update(JSON.stringify(canonicalize(value))).digest("hex").slice(0, 32);
42729
42897
  }
42730
42898
  function resolveScopeHashes(scope) {
42731
42899
  const contextHash = scope?.cacheContext === void 0 ? "none" : hashValue(scope.cacheContext);
@@ -42735,10 +42903,10 @@ function resolveScopeHashes(scope) {
42735
42903
  function cacheFilePathScoped(twinName, baseSeedName, setupText, scope) {
42736
42904
  const normalizedSetup = normalizeSetupText(setupText);
42737
42905
  const { contextHash, baseSeedHash } = resolveScopeHashes(scope);
42738
- const key = (0, import_node_crypto12.createHash)("sha256").update(`${twinName}:${baseSeedName}:${normalizedSetup}:${contextHash}:${baseSeedHash}`).digest("hex").slice(0, 32);
42906
+ const key = (0, import_node_crypto13.createHash)("sha256").update(`${twinName}:${baseSeedName}:${normalizedSetup}:${contextHash}:${baseSeedHash}`).digest("hex").slice(0, 32);
42739
42907
  const intentHash = setupHash(normalizedSetup);
42740
42908
  return {
42741
- path: (0, import_node_path7.join)(CACHE_DIR, `${key}.json`),
42909
+ path: (0, import_node_path8.join)(CACHE_DIR, `${key}.json`),
42742
42910
  key,
42743
42911
  normalizedSetup,
42744
42912
  intentHash,
@@ -42747,25 +42915,25 @@ function cacheFilePathScoped(twinName, baseSeedName, setupText, scope) {
42747
42915
  };
42748
42916
  }
42749
42917
  function ensureCacheDir() {
42750
- if (!(0, import_node_fs8.existsSync)(CACHE_DIR)) {
42751
- (0, import_node_fs8.mkdirSync)(CACHE_DIR, { recursive: true });
42918
+ if (!(0, import_node_fs9.existsSync)(CACHE_DIR)) {
42919
+ (0, import_node_fs9.mkdirSync)(CACHE_DIR, { recursive: true });
42752
42920
  }
42753
42921
  }
42754
42922
  function evictStaleEntries() {
42755
42923
  try {
42756
- if (!(0, import_node_fs8.existsSync)(CACHE_DIR)) return;
42924
+ if (!(0, import_node_fs9.existsSync)(CACHE_DIR)) return;
42757
42925
  const now = Date.now();
42758
- for (const file2 of (0, import_node_fs8.readdirSync)(CACHE_DIR)) {
42926
+ for (const file2 of (0, import_node_fs9.readdirSync)(CACHE_DIR)) {
42759
42927
  if (!file2.endsWith(".json")) continue;
42760
- const filePath = (0, import_node_path7.join)(CACHE_DIR, file2);
42761
- const stat = (0, import_node_fs8.lstatSync)(filePath);
42928
+ const filePath = (0, import_node_path8.join)(CACHE_DIR, file2);
42929
+ const stat = (0, import_node_fs9.lstatSync)(filePath);
42762
42930
  if (stat.isSymbolicLink()) {
42763
42931
  debug3("Skipping symlink during cache eviction", { file: file2 });
42764
42932
  continue;
42765
42933
  }
42766
42934
  const age = now - stat.mtimeMs;
42767
42935
  if (age > MAX_AGE_MS) {
42768
- (0, import_node_fs8.unlinkSync)(filePath);
42936
+ (0, import_node_fs9.unlinkSync)(filePath);
42769
42937
  debug3("Evicted stale cache entry", { file: file2 });
42770
42938
  }
42771
42939
  }
@@ -42779,7 +42947,7 @@ function getCachedSeed(twinName, baseSeedName, setupText, scope) {
42779
42947
  const { path: filePath, key } = cacheFilePathScoped(twinName, baseSeedName, setupText, scope);
42780
42948
  let raw;
42781
42949
  try {
42782
- raw = (0, import_node_fs8.readFileSync)(filePath, "utf-8");
42950
+ raw = (0, import_node_fs9.readFileSync)(filePath, "utf-8");
42783
42951
  } catch {
42784
42952
  return null;
42785
42953
  }
@@ -42787,7 +42955,7 @@ function getCachedSeed(twinName, baseSeedName, setupText, scope) {
42787
42955
  if (entry.version !== SEED_CACHE_VERSION) {
42788
42956
  warn2(`Seed cache version mismatch (got ${entry.version}, want ${SEED_CACHE_VERSION}), evicting`);
42789
42957
  try {
42790
- (0, import_node_fs8.unlinkSync)(filePath);
42958
+ (0, import_node_fs9.unlinkSync)(filePath);
42791
42959
  } catch {
42792
42960
  }
42793
42961
  return null;
@@ -42798,7 +42966,7 @@ function getCachedSeed(twinName, baseSeedName, setupText, scope) {
42798
42966
  `Cached seed failed count verification, evicting: ${mismatches.map((m) => `${m.subject}: expected ${m.expected}, got ${m.actual}`).join("; ")}`
42799
42967
  );
42800
42968
  try {
42801
- (0, import_node_fs8.unlinkSync)(filePath);
42969
+ (0, import_node_fs9.unlinkSync)(filePath);
42802
42970
  } catch {
42803
42971
  }
42804
42972
  return null;
@@ -42850,8 +43018,8 @@ function cacheSeed(twinName, baseSeedName, setupText, seed, patch, scope, genera
42850
43018
  ...generatedCode !== void 0 && { generatedCode }
42851
43019
  };
42852
43020
  const tmpPath = `${filePath}.tmp`;
42853
- (0, import_node_fs8.writeFileSync)(tmpPath, JSON.stringify(entry));
42854
- (0, import_node_fs8.renameSync)(tmpPath, filePath);
43021
+ (0, import_node_fs9.writeFileSync)(tmpPath, JSON.stringify(entry));
43022
+ (0, import_node_fs9.renameSync)(tmpPath, filePath);
42855
43023
  debug3("Seed cached", { twin: twinName, baseSeed: baseSeedName, key });
42856
43024
  } catch (err) {
42857
43025
  warn2(`Failed to write seed cache entry: ${errorMessage2(err)}`);
@@ -42874,6 +43042,8 @@ IMPORTANT CONSTRAINTS:
42874
43042
  - For RLS policies, use simple expressions like: USING (true) or USING (current_setting('app.user_id')::int = user_id)
42875
43043
  - Use serial or bigserial for primary keys, not uuid (unless explicitly asked)
42876
43044
  - Use simple types: text, int, boolean, timestamptz
43045
+ - Do NOT use JSON-style array literals like ["a", "b"] in INSERT values.
43046
+ Use ARRAY['a', 'b'] for SQL array columns, or quoted JSON with ::jsonb for jsonb columns.
42877
43047
  - Always include INSERT statements with realistic test data
42878
43048
 
42879
43049
 
@@ -42894,6 +43064,222 @@ INSERT INTO users (email, name, role) VALUES
42894
43064
  ALTER TABLE users ENABLE ROW LEVEL SECURITY;
42895
43065
  CREATE POLICY "users_select" ON users FOR SELECT USING (true);
42896
43066
  CREATE POLICY "users_update_own" ON users FOR UPDATE USING (id = current_setting('app.user_id', true)::int);`;
43067
+ function sqlLiteral2(value) {
43068
+ if (value === null || value === void 0) return "NULL";
43069
+ if (typeof value === "number") return Number.isFinite(value) ? String(value) : "NULL";
43070
+ if (typeof value === "boolean") return value ? "TRUE" : "FALSE";
43071
+ return `'${String(value).replace(/'/g, "''")}'`;
43072
+ }
43073
+ function sqlIdent2(value) {
43074
+ if (!value) throw new Error("SQL identifier must not be empty");
43075
+ if (value.includes("\0")) throw new Error("SQL identifier must not contain null bytes");
43076
+ return `"${value.replace(/"/g, '""')}"`;
43077
+ }
43078
+ function sqlValueLiteral(value, columnType) {
43079
+ const type = columnType?.toLowerCase() ?? "";
43080
+ if (Array.isArray(value)) {
43081
+ if (type.includes("[]")) {
43082
+ const baseType = type.replace(/\[\].*$/, "") || "text";
43083
+ if (value.length === 0) return `ARRAY[]::${baseType}[]`;
43084
+ return `ARRAY[${value.map(sqlLiteral2).join(", ")}]`;
43085
+ }
43086
+ const json2 = sqlLiteral2(JSON.stringify(value));
43087
+ if (type.includes("jsonb")) return `${json2}::jsonb`;
43088
+ if (type.includes("json")) return `${json2}::json`;
43089
+ return json2;
43090
+ }
43091
+ if (value && typeof value === "object") {
43092
+ const json2 = sqlLiteral2(JSON.stringify(value));
43093
+ if (type.includes("jsonb")) return `${json2}::jsonb`;
43094
+ if (type.includes("json")) return `${json2}::json`;
43095
+ return json2;
43096
+ }
43097
+ return sqlLiteral2(value);
43098
+ }
43099
+ function splitSqlTopLevel(input, separator) {
43100
+ const parts = [];
43101
+ let depth = 0;
43102
+ let bracketDepth = 0;
43103
+ let inQuote = false;
43104
+ let start = 0;
43105
+ for (let i = 0; i < input.length; i++) {
43106
+ const ch = input[i];
43107
+ if (ch === void 0) continue;
43108
+ const next = i + 1 < input.length ? input[i + 1] : void 0;
43109
+ if (ch === "'") {
43110
+ if (inQuote && next === "'") {
43111
+ i += 1;
43112
+ continue;
43113
+ }
43114
+ inQuote = !inQuote;
43115
+ continue;
43116
+ }
43117
+ if (inQuote) continue;
43118
+ if (ch === "(") depth += 1;
43119
+ else if (ch === ")") depth = Math.max(0, depth - 1);
43120
+ else if (ch === "[") bracketDepth += 1;
43121
+ else if (ch === "]") bracketDepth = Math.max(0, bracketDepth - 1);
43122
+ if (depth === 0 && bracketDepth === 0 && ch === separator) {
43123
+ parts.push(input.slice(start, i).trim());
43124
+ start = i + 1;
43125
+ }
43126
+ }
43127
+ const tail = input.slice(start).trim();
43128
+ if (tail) parts.push(tail);
43129
+ return parts;
43130
+ }
43131
+ function splitSqlStatements(sql) {
43132
+ return splitSqlTopLevel(sql, ";").map((statement) => statement.trim()).filter(Boolean);
43133
+ }
43134
+ function normalizeSqlIdentifier(raw) {
43135
+ const parts = raw.split(".").map((part) => part.trim().replace(/^"|"$/g, "").replace(/""/g, '"')).filter(Boolean);
43136
+ return parts[parts.length - 1] ?? raw.trim();
43137
+ }
43138
+ function collectTableSchemas(sql) {
43139
+ const tableSchemas = /* @__PURE__ */ new Map();
43140
+ for (const statement of splitSqlStatements(sql)) {
43141
+ const match = statement.match(
43142
+ /^CREATE\s+TABLE(?:\s+IF\s+NOT\s+EXISTS)?\s+([^\s(]+)\s*\(([\s\S]*)\)$/i
43143
+ );
43144
+ if (!match?.[1] || !match[2]) continue;
43145
+ const columnTypes = /* @__PURE__ */ new Map();
43146
+ const columnOrder = [];
43147
+ for (const columnDef of splitSqlTopLevel(match[2], ",")) {
43148
+ const columnMatch = columnDef.trim().match(/^("(?:""|[^"])+"|[a-zA-Z_][a-zA-Z0-9_]*)\s+([a-zA-Z0-9_."[\]]+)/);
43149
+ if (!columnMatch?.[1] || !columnMatch[2]) continue;
43150
+ const columnName = normalizeSqlIdentifier(columnMatch[1]);
43151
+ columnTypes.set(columnName, columnMatch[2].toLowerCase());
43152
+ columnOrder.push(columnName);
43153
+ }
43154
+ tableSchemas.set(normalizeSqlIdentifier(match[1]), { columnTypes, columnOrder });
43155
+ }
43156
+ return tableSchemas;
43157
+ }
43158
+ function normalizeJsonArrayLiteral(value, columnType) {
43159
+ const trimmed = value.trim();
43160
+ if (!trimmed.startsWith("[") || !trimmed.endsWith("]")) return value;
43161
+ let parsed;
43162
+ try {
43163
+ parsed = JSON.parse(trimmed);
43164
+ } catch {
43165
+ return value;
43166
+ }
43167
+ if (!Array.isArray(parsed)) return value;
43168
+ const type = columnType?.toLowerCase() ?? "";
43169
+ if (type.includes("[]")) {
43170
+ const baseType = type.replace(/\[\].*$/, "") || "text";
43171
+ if (parsed.length === 0) return `ARRAY[]::${baseType}[]`;
43172
+ return `ARRAY[${parsed.map(sqlLiteral2).join(", ")}]`;
43173
+ }
43174
+ const json2 = sqlLiteral2(JSON.stringify(parsed));
43175
+ if (type.includes("jsonb")) return `${json2}::jsonb`;
43176
+ if (type.includes("json")) return `${json2}::json`;
43177
+ return json2;
43178
+ }
43179
+ function renderStructuredTableSql(value) {
43180
+ const tables = Array.isArray(value) ? value : value && typeof value === "object" && Array.isArray(value["tables"]) ? value["tables"] : null;
43181
+ if (!Array.isArray(tables)) return null;
43182
+ const statements = [];
43183
+ for (const table of tables) {
43184
+ if (!table || typeof table !== "object") return null;
43185
+ const record2 = table;
43186
+ const tableName = typeof record2["name"] === "string" ? record2["name"] : void 0;
43187
+ const columns = Array.isArray(record2["columns"]) ? record2["columns"] : void 0;
43188
+ if (!tableName || !columns) return null;
43189
+ const columnTypes = /* @__PURE__ */ new Map();
43190
+ const columnDefinitions = columns.map((column) => {
43191
+ if (!column || typeof column !== "object") throw new Error("invalid column");
43192
+ const columnRecord = column;
43193
+ const name = typeof columnRecord["name"] === "string" ? columnRecord["name"] : void 0;
43194
+ const rawType = typeof columnRecord["type"] === "string" ? columnRecord["type"] : "text";
43195
+ if (!name) throw new Error("invalid column name");
43196
+ const isPrimary = columnRecord["is_primary"] === true || columnRecord["primary"] === true;
43197
+ const type = isPrimary && /^(bigint|int|integer|serial|bigserial)$/i.test(rawType) ? "bigserial" : rawType;
43198
+ columnTypes.set(name, type);
43199
+ return `${sqlIdent2(name)} ${type}${isPrimary ? " PRIMARY KEY" : ""}`;
43200
+ });
43201
+ statements.push(`CREATE TABLE IF NOT EXISTS public.${sqlIdent2(tableName)} (${columnDefinitions.join(", ")});`);
43202
+ const rows = Array.isArray(record2["rows"]) ? record2["rows"] : Array.isArray(record2["data"]) ? record2["data"] : [];
43203
+ for (const row of rows) {
43204
+ if (!row || typeof row !== "object") continue;
43205
+ const entries = Object.entries(row).filter(([column]) => columnTypes.has(column));
43206
+ if (entries.length === 0) continue;
43207
+ statements.push(
43208
+ `INSERT INTO public.${sqlIdent2(tableName)} (${entries.map(([column]) => sqlIdent2(column)).join(", ")}) VALUES (${entries.map(([column, rowValue]) => sqlValueLiteral(rowValue, columnTypes.get(column))).join(", ")});`
43209
+ );
43210
+ }
43211
+ }
43212
+ return statements.length > 0 ? statements.join("\n\n") : null;
43213
+ }
43214
+ function normalizeCreateTableStatement(statement) {
43215
+ const match = statement.match(
43216
+ /^(CREATE\s+TABLE(?:\s+IF\s+NOT\s+EXISTS)?\s+[^\s(]+\s*)\(([\s\S]*)\)$/i
43217
+ );
43218
+ if (!match?.[1] || !match[2]) return statement;
43219
+ const columnDefs = splitSqlTopLevel(match[2], ",").map((columnDef) => {
43220
+ const columnMatch = columnDef.trim().match(
43221
+ /^("(?:""|[^"])+"|[a-zA-Z_][a-zA-Z0-9_]*)\s+([a-zA-Z0-9_."[\]]+)([\s\S]*)$/i
43222
+ );
43223
+ if (!columnMatch?.[2] || !columnMatch[3]) return columnDef;
43224
+ const columnType = columnMatch[2].toLowerCase();
43225
+ const rest = columnMatch[3].replace(
43226
+ /\bDEFAULT\s+(\[[\s\S]*?\])(?=\s|,|$)/i,
43227
+ (_full, value) => `DEFAULT ${normalizeJsonArrayLiteral(value, columnType)}`
43228
+ );
43229
+ return `${columnMatch[1]} ${columnMatch[2]}${rest}`;
43230
+ });
43231
+ return `${match[1]}(${columnDefs.join(", ")})`;
43232
+ }
43233
+ function normalizeSupabaseSql(sql) {
43234
+ const tableSchemas = collectTableSchemas(sql);
43235
+ return splitSqlStatements(sql).map((statement) => {
43236
+ if (/^CREATE\s+TABLE/i.test(statement)) return normalizeCreateTableStatement(statement);
43237
+ const match = statement.match(/^INSERT\s+INTO\s+([^\s(]+)\s*\(([^)]+)\)\s*VALUES\s*([\s\S]*)$/i) ?? statement.match(/^INSERT\s+INTO\s+([^\s(]+)\s+VALUES\s*([\s\S]*)$/i);
43238
+ if (!match?.[1]) return statement;
43239
+ const tableName = normalizeSqlIdentifier(match[1]);
43240
+ const hasColumnList = match.length === 4;
43241
+ const valuesSql = hasColumnList ? match[3] : match[2];
43242
+ if (!valuesSql) return statement;
43243
+ const schema = tableSchemas.get(tableName);
43244
+ const columns = hasColumnList ? splitSqlTopLevel(match[2] ?? "", ",").map(normalizeSqlIdentifier) : schema?.columnOrder ?? [];
43245
+ const tuples = [];
43246
+ let depth = 0;
43247
+ let bracketDepth = 0;
43248
+ let inQuote = false;
43249
+ let tupleStart = -1;
43250
+ for (let i = 0; i < valuesSql.length; i++) {
43251
+ const ch = valuesSql[i];
43252
+ if (ch === void 0) continue;
43253
+ const next = i + 1 < valuesSql.length ? valuesSql[i + 1] : void 0;
43254
+ if (ch === "'") {
43255
+ if (inQuote && next === "'") {
43256
+ i += 1;
43257
+ continue;
43258
+ }
43259
+ inQuote = !inQuote;
43260
+ }
43261
+ if (inQuote) continue;
43262
+ if (ch === "[") bracketDepth += 1;
43263
+ else if (ch === "]") bracketDepth = Math.max(0, bracketDepth - 1);
43264
+ else if (ch === "(" && bracketDepth === 0) {
43265
+ if (depth === 0) tupleStart = i + 1;
43266
+ depth += 1;
43267
+ } else if (ch === ")" && bracketDepth === 0) {
43268
+ depth -= 1;
43269
+ if (depth === 0 && tupleStart >= 0) {
43270
+ tuples.push(valuesSql.slice(tupleStart, i));
43271
+ tupleStart = -1;
43272
+ }
43273
+ }
43274
+ }
43275
+ if (tuples.length === 0) return statement;
43276
+ const normalizedTuples = tuples.map((tuple2) => {
43277
+ const values = splitSqlTopLevel(tuple2, ",").map((value, index) => normalizeJsonArrayLiteral(value, schema?.columnTypes.get(columns[index] ?? "")));
43278
+ return `(${values.join(", ")})`;
43279
+ });
43280
+ return hasColumnList ? `INSERT INTO ${match[1]} (${match[2]}) VALUES ${normalizedTuples.join(", ")}` : `INSERT INTO ${match[1]} VALUES ${normalizedTuples.join(", ")}`;
43281
+ }).join(";\n") + ";";
43282
+ }
42897
43283
  function extractSupabaseSql(response) {
42898
43284
  let sql = response.trim();
42899
43285
  if (sql.startsWith("```")) {
@@ -42902,24 +43288,35 @@ function extractSupabaseSql(response) {
42902
43288
  if (sql.startsWith("{")) {
42903
43289
  try {
42904
43290
  const parsed = JSON.parse(sql);
43291
+ const structuredSql = renderStructuredTableSql(parsed);
43292
+ if (structuredSql) return normalizeSupabaseSql(structuredSql);
42905
43293
  const extracted = parsed["sql"] ?? parsed["query"] ?? parsed["script"] ?? parsed["content"];
42906
- if (extracted && typeof extracted === "string") return extracted;
43294
+ if (extracted && typeof extracted === "string") return normalizeSupabaseSql(extracted);
43295
+ } catch {
43296
+ }
43297
+ }
43298
+ if (sql.startsWith('"')) {
43299
+ try {
43300
+ const parsed = JSON.parse(sql);
43301
+ if (typeof parsed === "string") return normalizeSupabaseSql(parsed);
42907
43302
  } catch {
42908
43303
  }
42909
43304
  }
42910
43305
  if (sql.startsWith("[")) {
42911
43306
  try {
42912
43307
  const parsed = JSON.parse(sql);
43308
+ const structuredSql = renderStructuredTableSql(parsed);
43309
+ if (structuredSql) return normalizeSupabaseSql(structuredSql);
42913
43310
  const parts = [];
42914
43311
  for (const item of parsed) {
42915
43312
  const s = item["sql"] ?? item["query"] ?? item["script"];
42916
43313
  if (s && typeof s === "string") parts.push(s);
42917
43314
  }
42918
- if (parts.length > 0) return parts.join("\n\n");
43315
+ if (parts.length > 0) return normalizeSupabaseSql(parts.join("\n\n"));
42919
43316
  } catch {
42920
43317
  }
42921
43318
  }
42922
- return sql;
43319
+ return normalizeSupabaseSql(sql);
42923
43320
  }
42924
43321
 
42925
43322
  // ../packages/seedgen/src/runtime/session-context.ts
@@ -43264,7 +43661,7 @@ async function enrichSeedWithLlm(seed, twinName, setupDescription, deadline, coo
43264
43661
  try {
43265
43662
  const response = await callCodegenLlm({
43266
43663
  systemPrompt: ENRICH_SYSTEM_PROMPT,
43267
- userPrompt: `Twin: ${twinName}
43664
+ userPrompt: `Clone: ${twinName}
43268
43665
 
43269
43666
  Setup description:
43270
43667
  ${setupDescription}
@@ -43285,7 +43682,7 @@ ${snapshot}${buildFewShotExample(twinName)}`,
43285
43682
  }
43286
43683
 
43287
43684
  // ../packages/seedgen/src/runner/seed/key-fixer.ts
43288
- var import_node_crypto13 = require("crypto");
43685
+ var import_node_crypto14 = require("crypto");
43289
43686
  function parseIssueKey(value) {
43290
43687
  const match = value.match(/^([A-Z]{2,})-(\d+)$/);
43291
43688
  if (!match || !match[1] || !match[2]) return null;
@@ -43551,7 +43948,7 @@ function fixIssueKeys(seed, intent, twinName, options) {
43551
43948
  newIssue[issueKeyField] = expectedKey;
43552
43949
  newIssue[fkField] = projectId;
43553
43950
  if (isLinear) {
43554
- newIssue["linearId"] = (0, import_node_crypto13.randomUUID)();
43951
+ newIssue["linearId"] = (0, import_node_crypto14.randomUUID)();
43555
43952
  newIssue["title"] = `Issue ${expectedKey}`;
43556
43953
  } else {
43557
43954
  newIssue["summary"] = `Issue ${expectedKey}`;
@@ -44442,6 +44839,10 @@ var GOOGLE_WORKSPACE_BOOTSTRAP_SCOPES = [
44442
44839
  "https://www.googleapis.com/auth/drive.readonly",
44443
44840
  "https://www.googleapis.com/auth/contacts.readonly"
44444
44841
  ];
44842
+ var GOOGLE_WORKSPACE_SYNTHETIC_EMAIL = "self@local.invalid";
44843
+ function isSyntheticGoogleWorkspaceEmail(email3) {
44844
+ return email3 === GOOGLE_WORKSPACE_SYNTHETIC_EMAIL;
44845
+ }
44445
44846
  function googleWorkspaceEmailEntities(intent) {
44446
44847
  if (!intent || intent.twinName !== "google-workspace") return [];
44447
44848
  return intent.entities.filter((entity) => entity.kind === "email" && entity.key === "address" && typeof entity.value === "string" || entity.kind === "account" && entity.key === "email" && typeof entity.value === "string").map((entity) => normalizedEmail(entity.value)).filter((value) => Boolean(value));
@@ -44469,6 +44870,32 @@ function googleWorkspaceReferencedEmails(seed) {
44469
44870
  }
44470
44871
  return emails;
44471
44872
  }
44873
+ function googleWorkspaceBootstrapEmail(intentEmails, referencedEmails) {
44874
+ return intentEmails.find((email3) => !isSyntheticGoogleWorkspaceEmail(email3)) ?? referencedEmails.find((email3) => !isSyntheticGoogleWorkspaceEmail(email3)) ?? "user@example.com";
44875
+ }
44876
+ function rewriteSyntheticGoogleWorkspaceAccountRefs(seed, email3) {
44877
+ const collections = [
44878
+ "calendars",
44879
+ "calendarEvents",
44880
+ "gmailThreads",
44881
+ "gmailMessages",
44882
+ "gmailDrafts",
44883
+ "gmailAttachments",
44884
+ "gmailHistory",
44885
+ "driveFiles",
44886
+ "contacts",
44887
+ "googleAuthTokens"
44888
+ ];
44889
+ for (const collection of collections) {
44890
+ for (const item of seed[collection] ?? []) {
44891
+ const record2 = asRecord(item);
44892
+ if (!record2) continue;
44893
+ if (isSyntheticGoogleWorkspaceEmail(normalizedEmail(record2["accountEmail"]))) {
44894
+ record2["accountEmail"] = email3;
44895
+ }
44896
+ }
44897
+ }
44898
+ }
44472
44899
  function googleWorkspaceHasCalendarSurface(intent) {
44473
44900
  return intent.extractedSlots["workspace.surface.calendar"] === true || /\b(calendar|event|events|meeting|meetings|invite|invites)\b/i.test(intent.setupSummary);
44474
44901
  }
@@ -44503,6 +44930,15 @@ function ensureGoogleWorkspaceAccount(accounts, email3, primary) {
44503
44930
  primary
44504
44931
  });
44505
44932
  }
44933
+ function replaceGoogleWorkspaceAccount(account, email3) {
44934
+ account["accountId"] = "acct_primary";
44935
+ account["email"] = email3;
44936
+ account["displayName"] = "Primary Account";
44937
+ account["givenName"] = "Primary";
44938
+ account["familyName"] = "Account";
44939
+ account["timezone"] = "America/Los_Angeles";
44940
+ account["primary"] = true;
44941
+ }
44506
44942
  function ensureGoogleWorkspaceAuthToken(authTokens, email3) {
44507
44943
  if (authTokens.some((token) => normalizedEmail(token["accountEmail"]) === email3)) return;
44508
44944
  const localPart = email3.split("@")[0] ?? email3;
@@ -44522,7 +44958,8 @@ function ensureGoogleWorkspaceAuthToken(authTokens, email3) {
44522
44958
  function ensureGoogleWorkspacePrimaryCalendar(calendars, accountEmail) {
44523
44959
  const existingPrimary = calendars.find((calendar) => calendar["calendarId"] === "primary");
44524
44960
  if (existingPrimary) {
44525
- existingPrimary["accountEmail"] = normalizedEmail(existingPrimary["accountEmail"]) ?? accountEmail;
44961
+ const existingEmail = normalizedEmail(existingPrimary["accountEmail"]);
44962
+ existingPrimary["accountEmail"] = !existingEmail || isSyntheticGoogleWorkspaceEmail(existingEmail) ? accountEmail : existingEmail;
44526
44963
  existingPrimary["primary"] = true;
44527
44964
  return "primary";
44528
44965
  }
@@ -44547,6 +44984,15 @@ function ensureGoogleWorkspaceCalendarRows(mergedSeed) {
44547
44984
  for (const item of mergedSeed["calendarEvents"] ?? []) {
44548
44985
  const event = asRecord(item);
44549
44986
  if (!event) continue;
44987
+ if (typeof event["summary"] !== "string") {
44988
+ event["summary"] = "Calendar event";
44989
+ }
44990
+ if (typeof event["description"] !== "string") {
44991
+ event["description"] = "";
44992
+ }
44993
+ if (typeof event["location"] !== "string") {
44994
+ event["location"] = "";
44995
+ }
44550
44996
  const calendarId = typeof event["calendarId"] === "string" && event["calendarId"].trim() ? event["calendarId"].trim() : "primary";
44551
44997
  const accountEmail = normalizedEmail(event["accountEmail"]) ?? "self@local.invalid";
44552
44998
  if (existingCalendarIds.has(calendarId)) continue;
@@ -44586,21 +45032,28 @@ function ensureGoogleWorkspaceCalendarEvidence(mergedSeed, intent, accountEmail)
44586
45032
  organizerEmail: accountEmail,
44587
45033
  attendeeEmails: [],
44588
45034
  conferenceUrl: null,
44589
- extendedPropertiesShared: null
45035
+ extendedPropertiesShared: {}
44590
45036
  });
44591
45037
  }
44592
45038
  function ensureGoogleWorkspaceScenarioAccounts(mergedSeed, intent) {
44593
45039
  if (!intent || intent.twinName !== "google-workspace") return mergedSeed;
44594
45040
  const accounts = ensureArray(mergedSeed, "accounts");
44595
45041
  const authTokens = ensureArray(mergedSeed, "googleAuthTokens");
45042
+ const intentEmails = googleWorkspaceEmailEntities(intent);
45043
+ let referencedEmails = googleWorkspaceReferencedEmails(mergedSeed);
45044
+ const bootstrapEmail = googleWorkspaceBootstrapEmail(intentEmails, referencedEmails);
44596
45045
  if (accounts.length === 0) {
44597
- ensureGoogleWorkspaceAccount(accounts, "self@local.invalid", true);
45046
+ ensureGoogleWorkspaceAccount(accounts, bootstrapEmail, true);
45047
+ } else if (accounts.length === 1 && isSyntheticGoogleWorkspaceEmail(normalizedEmail(accounts[0]?.["email"]))) {
45048
+ replaceGoogleWorkspaceAccount(accounts[0], bootstrapEmail);
44598
45049
  }
44599
- const primaryEmail = normalizedEmail(accounts.find((account) => account["primary"] === true)?.["email"]) ?? normalizedEmail(accounts[0]?.["email"]) ?? "self@local.invalid";
45050
+ rewriteSyntheticGoogleWorkspaceAccountRefs(mergedSeed, bootstrapEmail);
45051
+ referencedEmails = googleWorkspaceReferencedEmails(mergedSeed);
45052
+ const primaryEmail = normalizedEmail(accounts.find((account) => account["primary"] === true)?.["email"]) ?? normalizedEmail(accounts[0]?.["email"]) ?? GOOGLE_WORKSPACE_SYNTHETIC_EMAIL;
44600
45053
  ensureGoogleWorkspaceAuthToken(authTokens, primaryEmail);
44601
45054
  const requiredEmails = Array.from(/* @__PURE__ */ new Set([
44602
- ...googleWorkspaceEmailEntities(intent),
44603
- ...googleWorkspaceReferencedEmails(mergedSeed),
45055
+ ...intentEmails,
45056
+ ...referencedEmails,
44604
45057
  ...accounts.map((account) => normalizedEmail(account["email"])).filter((value) => Boolean(value))
44605
45058
  ]));
44606
45059
  for (const email3 of requiredEmails) {
@@ -44627,7 +45080,7 @@ var DynamicSeedError = class extends Error {
44627
45080
  const details = validationErrors.length > 0 ? `:
44628
45081
  ${validationErrors.map((e) => ` - ${e}`).join("\n")}` : ".";
44629
45082
  const suffix = hint ?? "\n\nHint: Run `archal login` and retry. For deterministic reruns, use `--replay-seed <path>` with a previously saved managed seed snapshot.";
44630
- super(`Dynamic seed generation failed for twin "${twinName}"${details}${suffix}`);
45083
+ super(`Dynamic seed generation failed for clone "${twinName}"${details}${suffix}`);
44631
45084
  this.name = "DynamicSeedError";
44632
45085
  this.twinName = twinName;
44633
45086
  this.validationErrors = validationErrors;
@@ -44693,7 +45146,7 @@ ${fkDetails}
44693
45146
  // ../packages/seedgen/src/runner/seed/dynamic-generator.ts
44694
45147
  var SEED_CODEGEN_MAX_TOKENS = 4096;
44695
45148
  var MAX_CODEGEN_ATTEMPTS = 3;
44696
- var SEED_CACHE_PROMPT_TEMPLATE_VERSION = 4;
45149
+ var SEED_CACHE_PROMPT_TEMPLATE_VERSION = 5;
44697
45150
  var CODEGEN_TOTAL_BUDGET_MS = 12e4;
44698
45151
  function buildSeedCacheContext(twinName, systemPromptHash, intent, context) {
44699
45152
  return {
@@ -45102,7 +45555,7 @@ function buildSeedPromptHashInput() {
45102
45555
  SUPABASE_SQL_SYSTEM_PROMPT
45103
45556
  ].join("\n\n---\n\n");
45104
45557
  }
45105
- var SYSTEM_PROMPT_HASH = (0, import_node_crypto14.createHash)("sha256").update(buildSeedPromptHashInput()).digest("hex").slice(0, 12);
45558
+ var SYSTEM_PROMPT_HASH = (0, import_node_crypto15.createHash)("sha256").update(buildSeedPromptHashInput()).digest("hex").slice(0, 12);
45106
45559
  async function generateDynamicSeed(twinName, baseSeedName, baseSeedData, setupDescription, config2, intent, context) {
45107
45560
  const scopedSetupDescription = config2.skipTwinScoping ? setupDescription : scopeSetupToTwin(twinName, setupDescription);
45108
45561
  const seedIntent = resolveSeedIntentForGeneration(twinName, scopedSetupDescription, intent);
@@ -45222,8 +45675,8 @@ async function generateDynamicSeed(twinName, baseSeedName, baseSeedData, setupDe
45222
45675
  ],
45223
45676
  `
45224
45677
 
45225
- Hint: Dynamic seed generation failed for the "${twinName}" twin. Try adding a \`seed: <name>\` line to your scenario's Config section to use a pre-built seed instead.
45226
- Use a documented seed name for ${twinName}, or inspect the twin package assets in this repo.`
45678
+ Hint: Dynamic seed generation failed for the "${twinName}" clone. Try adding a \`seed: <name>\` line to your scenario's Config section to use a pre-built seed instead.
45679
+ Use a documented seed name for ${twinName}, or inspect the bundled clone assets in this repo.`
45227
45680
  );
45228
45681
  }
45229
45682
  // Annotate the CommonJS export names for ESM import in node: