archal 0.9.20 → 0.10.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 (90) hide show
  1. package/README.md +59 -159
  2. package/agents/openclaw/Dockerfile +2 -1
  3. package/agents/openclaw/README.md +10 -17
  4. package/agents/openclaw/drive.mjs +21 -31
  5. package/agents/openclaw/extract-openclaw-response-text.mjs +49 -0
  6. package/agents/openclaw/scenarios/acceptance/github-escalation-and-cleanup.md +43 -0
  7. package/agents/openclaw/scenarios/acceptance/jira-linear-release-triage.md +39 -0
  8. package/agents/openclaw/scenarios/acceptance/multi-clone-customer-risk-review.md +45 -0
  9. package/agents/openclaw/scenarios/acceptance/slack-incident-handoff.md +42 -0
  10. package/agents/openclaw/scenarios/acceptance/stripe-dunning-remediation.md +40 -0
  11. package/agents/openclaw/scenarios/close-stale-issues.md +35 -0
  12. package/agents/openclaw/workspace/TOOLS.md +19 -0
  13. package/clone-assets/calcom/tools.json +1705 -153
  14. package/clone-assets/clickup/tools.json +2528 -541
  15. package/clone-assets/customerio/tools.json +2108 -144
  16. package/clone-assets/github/tools.json +1 -2
  17. package/clone-assets/gitlab/tools.json +10087 -398
  18. package/clone-assets/hubspot/tools.json +198 -0
  19. package/clone-assets/linear/tools.json +41 -1
  20. package/clone-assets/sentry/tools.json +2264 -188
  21. package/clone-assets/stripe/tools.json +114 -0
  22. package/clone-assets/webflow/tools.json +1895 -125
  23. package/dist/{autoloop-worker-types-BEb_E44z.d.cts → autoloop-worker-types-CHaclqtD.d.cts} +23 -59
  24. package/dist/cli.cjs +107175 -126959
  25. package/dist/commands/{autoloop-hosted-worker.cjs → autoloop-hosted-control-plane-client.cjs} +25657 -42736
  26. package/dist/commands/{autoloop-hosted-worker.d.cts → autoloop-hosted-control-plane-client.d.cts} +32 -42
  27. package/dist/commands/autoloop-pr-verification.cjs +607 -522
  28. package/dist/commands/autoloop-pr-verification.d.cts +3 -1
  29. package/dist/commands/autoloop-result-parser.cjs +2474 -2373
  30. package/dist/commands/autoloop-result-parser.d.cts +159 -2
  31. package/dist/commands/autoloop-worker.cjs +14565 -12240
  32. package/dist/commands/autoloop-worker.d.cts +10 -5
  33. package/dist/eval-shim.mjs +216 -0
  34. package/dist/index.cjs +15 -2
  35. package/dist/index.d.cts +3 -1
  36. package/dist/layer-1-ziaLpfLr.d.cts +62 -0
  37. package/dist/metafile-cjs.json +1 -0
  38. package/dist/reporter-entry.js +3 -0
  39. package/dist/{replay.cjs → sdk/index.cjs} +42979 -40973
  40. package/dist/sdk/index.d.cts +626 -0
  41. package/dist/vitest/{chunk-6CBYFCFK.js → chunk-2PDHTPZC.js} +289 -89
  42. package/dist/vitest/{chunk-ARVS45PP.js → chunk-7L4BBB6M.js} +123 -274
  43. package/dist/vitest/index.cjs +500 -816
  44. package/dist/vitest/index.d.ts +16 -81
  45. package/dist/vitest/index.js +40 -409
  46. package/dist/vitest/runtime/hosted-session-reaper.cjs +143 -293
  47. package/dist/vitest/runtime/hosted-session-reaper.js +1 -1
  48. package/dist/vitest/runtime/setup-files.js +2 -2
  49. package/manifest.json +9 -0
  50. package/package.json +14 -13
  51. package/skills/archal-agent/SKILL.md +0 -1
  52. package/skills/autoloop/SKILL.md +288 -273
  53. package/skills/autoloop/references/hosted-sources.md +49 -17
  54. package/skills/autoloop/references/trace-schema-mapping.md +83 -52
  55. package/skills/eval/SKILL.md +16 -48
  56. package/skills/free-account/SKILL.md +103 -0
  57. package/skills/install-agent/SKILL.md +16 -35
  58. package/skills/onboard/SKILL.md +13 -70
  59. package/skills/scenario/SKILL.md +30 -27
  60. package/skills/seed/SKILL.md +7 -6
  61. package/skills/vitest/SKILL.md +3 -2
  62. package/agents/github-octokit/.archal.json +0 -8
  63. package/agents/github-octokit/Dockerfile +0 -8
  64. package/agents/github-octokit/README.md +0 -113
  65. package/agents/github-octokit/agent.mjs +0 -54
  66. package/agents/github-octokit/package.json +0 -9
  67. package/agents/github-octokit/scenarios/test-repo-access.md +0 -27
  68. package/agents/google-workspace-local-tools/Dockerfile +0 -6
  69. package/agents/google-workspace-local-tools/README.md +0 -58
  70. package/agents/google-workspace-local-tools/agent.mjs +0 -196
  71. package/agents/google-workspace-local-tools/archal-harness.json +0 -7
  72. package/agents/google-workspace-local-tools/run-input.yaml +0 -16
  73. package/agents/google-workspace-local-tools/scenario.md +0 -29
  74. package/agents/hermes/.archal.json +0 -8
  75. package/agents/hermes/Dockerfile +0 -46
  76. package/agents/hermes/README.md +0 -87
  77. package/agents/hermes/SOUL.md +0 -27
  78. package/agents/hermes/config.yaml +0 -34
  79. package/agents/hermes/drive.mjs +0 -113
  80. package/agents/hermes/scenarios/stripe-customers-read-only.md +0 -32
  81. package/agents/pagination-test/README.md +0 -24
  82. package/agents/pagination-test/scenario.md +0 -24
  83. package/agents/replay-capsule-harness/README.md +0 -29
  84. package/agents/replay-capsule-harness/observability-install-offline-e2e.mts +0 -1517
  85. package/agents/replay-capsule-harness/replay-capsule-e2e.mjs +0 -104
  86. package/dist/harness.cjs +0 -63
  87. package/dist/harness.d.cts +0 -20
  88. package/dist/replay.d.cts +0 -4625
  89. package/dist/scenarios.cjs +0 -80343
  90. package/dist/scenarios.d.cts +0 -562
@@ -136,26 +136,6 @@ function parsePositiveInteger(rawValue, fallback, minimum = 1) {
136
136
  const parsed = Number(normalized);
137
137
  return Number.isSafeInteger(parsed) && parsed >= minimum ? parsed : fallback;
138
138
  }
139
- function normalizeApiBaseUrl(value) {
140
- if (!value) return null;
141
- const normalized = value.trim().replace(/\/+$/, "");
142
- if (!normalized) return null;
143
- let parsed;
144
- try {
145
- parsed = new URL(normalized);
146
- } catch {
147
- throw new Error(`Invalid ARCHAL_API_URL: "${normalized}" is not a valid URL`);
148
- }
149
- const isLocalhostHttp = parsed.protocol === "http:" && (parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1");
150
- if (parsed.protocol !== "https:" && !isLocalhostHttp) {
151
- throw new Error(`Hosted API URL must use HTTPS (or localhost HTTP). Received ${normalized}.`);
152
- }
153
- const pathname = parsed.pathname.replace(/\/+$/, "");
154
- parsed.pathname = pathname.endsWith("/api") ? pathname.slice(0, -4) || "/" : pathname || "/";
155
- parsed.search = "";
156
- parsed.hash = "";
157
- return parsed.toString().replace(/\/$/, "");
158
- }
159
139
  function resolveHostedWorkspaceHeader() {
160
140
  return trimEnv("ARCHAL_WORKSPACE_ID");
161
141
  }
@@ -652,6 +632,8 @@ var CREDENTIALS_MASTER_KEY_ENV_VAR = "ARCHAL_CREDENTIALS_MASTER_KEY";
652
632
  var KEYCHAIN_SERVICE = "archal-cli";
653
633
  var KEYCHAIN_ACCOUNT = "credentials-master-key";
654
634
  var HOSTED_DEFAULT_AUTH_BASE_URL = "https://www.archal.ai";
635
+ var HOSTED_DEFAULT_API_BASE_URL = "https://api.archal.ai";
636
+ var WORKSPACE_API_KEY_PREFIX = "archal_ws_";
655
637
  var STRICT_ENDPOINTS_ENV_VAR = "ARCHAL_STRICT_ENDPOINTS";
656
638
  var REQUEST_TIMEOUT_MS = 8e3;
657
639
  var ENV_TOKEN_FALLBACK_TTL_SECONDS = 24 * 60 * 60;
@@ -661,11 +643,6 @@ function isPlan(value) {
661
643
  return value === "free" || value === "pro" || value === "enterprise";
662
644
  }
663
645
 
664
- // ../node-auth/src/errors.ts
665
- function errorMessage2(error) {
666
- return error instanceof Error ? error.message : String(error);
667
- }
668
-
669
646
  // ../node-auth/src/credential-store.ts
670
647
  import { spawnSync } from "child_process";
671
648
  import { createCipheriv, createDecipheriv, createHash, randomBytes } from "crypto";
@@ -698,7 +675,7 @@ var GENERATED_CLONE_CATALOG = [
698
675
  name: "Cal.com",
699
676
  description: "Event types, schedules, availability slots, bookings, calendars, and webhooks.",
700
677
  stage: "preview",
701
- toolCount: 18,
678
+ toolCount: 35,
702
679
  transport: "both",
703
680
  architectureClass: "domain-simulator",
704
681
  domainPrimitives: [
@@ -716,7 +693,7 @@ var GENERATED_CLONE_CATALOG = [
716
693
  name: "ClickUp",
717
694
  description: "Teams, spaces, folders, lists, tasks, comments, tags, time tracking, and checklists.",
718
695
  stage: "preview",
719
- toolCount: 40,
696
+ toolCount: 123,
720
697
  transport: "both",
721
698
  architectureClass: "standard-core",
722
699
  domainPrimitives: [],
@@ -729,7 +706,7 @@ var GENERATED_CLONE_CATALOG = [
729
706
  name: "Customer.io",
730
707
  description: "Messaging automation across campaigns, broadcasts, transactional email, segments, customers, and message delivery.",
731
708
  stage: "preview",
732
- toolCount: 22,
709
+ toolCount: 129,
733
710
  transport: "rest",
734
711
  architectureClass: "standard-core",
735
712
  domainPrimitives: [],
@@ -794,7 +771,7 @@ var GENERATED_CLONE_CATALOG = [
794
771
  name: "GitLab",
795
772
  description: "Projects, branches, commits, issues, merge requests, pipelines, labels, milestones, releases, and webhooks.",
796
773
  stage: "preview",
797
- toolCount: 46,
774
+ toolCount: 559,
798
775
  transport: "both",
799
776
  architectureClass: "domain-simulator",
800
777
  domainPrimitives: [
@@ -829,7 +806,7 @@ var GENERATED_CLONE_CATALOG = [
829
806
  name: "HubSpot",
830
807
  description: "CRM contacts, companies, deals, tickets, and engagements.",
831
808
  stage: "preview",
832
- toolCount: 41,
809
+ toolCount: 44,
833
810
  transport: "rest",
834
811
  architectureClass: "replay-shell",
835
812
  domainPrimitives: [
@@ -864,7 +841,7 @@ var GENERATED_CLONE_CATALOG = [
864
841
  name: "Linear",
865
842
  description: "Issues, projects, teams, cycles, and workflows.",
866
843
  stage: "public",
867
- toolCount: 50,
844
+ toolCount: 53,
868
845
  transport: "both",
869
846
  architectureClass: "domain-simulator",
870
847
  domainPrimitives: [
@@ -933,7 +910,7 @@ var GENERATED_CLONE_CATALOG = [
933
910
  name: "Sentry",
934
911
  description: "Error monitoring across organizations, projects, teams, issues, events, releases, and DSN keys.",
935
912
  stage: "preview",
936
- toolCount: 25,
913
+ toolCount: 34,
937
914
  transport: "rest",
938
915
  architectureClass: "domain-simulator",
939
916
  domainPrimitives: [
@@ -1035,14 +1012,10 @@ var GENERATED_CLONE_CATALOG = [
1035
1012
  name: "Webflow",
1036
1013
  description: "Sites, pages, CMS collections, items, assets, forms, and webhooks.",
1037
1014
  stage: "preview",
1038
- toolCount: 19,
1039
- transport: "rest",
1040
- architectureClass: "replay-shell",
1041
- domainPrimitives: [
1042
- "recording replay cursor",
1043
- "CMS collection/item overlays",
1044
- "publish lifecycle captures"
1045
- ],
1015
+ toolCount: 104,
1016
+ transport: "both",
1017
+ architectureClass: "standard-core",
1018
+ domainPrimitives: [],
1046
1019
  behaviorOwner: null,
1047
1020
  opsCoverage: 100
1048
1021
  }
@@ -1138,142 +1111,11 @@ var STARTABLE_CLONE_CATALOG = CLONE_CATALOG.filter(
1138
1111
  (entry) => STARTABLE_CLONE_ID_SET.has(entry.id)
1139
1112
  );
1140
1113
 
1141
- // ../billing-constants/src/credit-catalog.ts
1142
- var CREDIT_COGS_MARKUP = 3;
1143
- var CREDIT_TARGET_GROSS_MARGIN_PERCENT = Math.round(
1144
- (1 - 1 / CREDIT_COGS_MARKUP) * 100
1145
- );
1146
-
1147
- // ../billing-constants/src/index.ts
1148
- var PLAN_MONTHLY_TWIN_MINUTE_LIMITS = {
1149
- free: 500,
1150
- pro: 5e3,
1151
- enterprise: null
1152
- };
1153
- var PLAN_CONCURRENT_SESSION_LIMITS = {
1154
- free: 3,
1155
- pro: 10,
1156
- enterprise: 50
1157
- };
1158
- var FREE_WORKSPACE_MEMBER_LIMIT = 2;
1159
- var PRO_PLAN_PRICE_USD = 199;
1160
- function formatMinutesLabel(minutes) {
1161
- return minutes.toLocaleString("en-US");
1162
- }
1163
- var FREE_MINUTES = PLAN_MONTHLY_TWIN_MINUTE_LIMITS.free;
1164
- var PRO_MINUTES = PLAN_MONTHLY_TWIN_MINUTE_LIMITS.pro;
1165
- if (FREE_MINUTES == null || PRO_MINUTES == null) {
1166
- throw new Error("PLAN_MONTHLY_TWIN_MINUTE_LIMITS: free and pro must be non-null");
1167
- }
1168
- var PRO_EVALS_PER_SEAT = 500;
1169
- var PRO_SESSION_MINUTES_PER_SEAT = 5e3;
1170
- var PRO_MAX_SEATS = 5;
1171
- var FREE_EVALS_PER_MONTH = 100;
1172
- var PLAN_DISPLAY = {
1173
- free: {
1174
- tag: "Free",
1175
- priceLabel: "$0",
1176
- periodLabel: "",
1177
- included: [
1178
- `${formatMinutesLabel(FREE_MINUTES)} session-minutes / account`,
1179
- `${FREE_EVALS_PER_MONTH} evals / account`,
1180
- `1 workspace (${FREE_WORKSPACE_MEMBER_LIMIT} users max)`,
1181
- `${PLAN_CONCURRENT_SESSION_LIMITS.free} concurrent sessions / workspace`,
1182
- "All clones included"
1183
- ]
1184
- },
1185
- pro: {
1186
- tag: "Pro",
1187
- priceLabel: `$${PRO_PLAN_PRICE_USD}`,
1188
- periodLabel: "/mo per seat",
1189
- included: [
1190
- `${formatMinutesLabel(PRO_SESSION_MINUTES_PER_SEAT)} session-minutes / seat / month`,
1191
- `${PRO_EVALS_PER_SEAT} evals / seat / month`,
1192
- "All clones included",
1193
- `${PLAN_CONCURRENT_SESSION_LIMITS.pro} concurrent sessions / workspace`,
1194
- `1 workspace, up to ${PRO_MAX_SEATS} seats with pooled usage`
1195
- ]
1196
- },
1197
- enterprise: {
1198
- tag: "Enterprise",
1199
- priceLabel: "Contact us",
1200
- periodLabel: "",
1201
- included: [
1202
- "Unlimited session-minutes",
1203
- "Unlimited seats per workspace",
1204
- "Unlimited workspaces",
1205
- `${PLAN_CONCURRENT_SESSION_LIMITS.enterprise} concurrent sessions / workspace`,
1206
- "SSO / SAML",
1207
- "SOC 2 (in progress)",
1208
- "Custom clones & eval support",
1209
- "Dedicated onboarding & support"
1210
- ]
1211
- }
1212
- };
1213
- var PLAN_MAX_SESSION_TTL_SECONDS = {
1214
- free: 30 * 60,
1215
- // 30 minutes
1216
- pro: 60 * 60,
1217
- // 60 minutes
1218
- enterprise: 90 * 60
1219
- // 90 minutes
1220
- };
1221
- var MAX_ABSOLUTE_SESSION_LIFETIME_SECONDS = 4 * 60 * 60;
1222
- var LIFETIME_PERIOD_RESETS_AT = new Date(Date.UTC(9999, 11, 31));
1223
- var ALL_ENTITLED_CLONES = ALL_STARTABLE_CLONE_IDS;
1224
- var SCENARIO_USAGE_WINDOW_DAYS = 7;
1225
- var SCENARIO_USAGE_WINDOW_MS = SCENARIO_USAGE_WINDOW_DAYS * 24 * 60 * 60 * 1e3;
1226
- var SCENARIO_USAGE_WINDOW_SECONDS = SCENARIO_USAGE_WINDOW_DAYS * 24 * 60 * 60;
1227
- var LLM_PRICING_USD_PER_M_TOKENS = {
1228
- // Google Gemini (verified 2026-05-05, standard tier <=200K input tokens)
1229
- "gemini-2.5-pro": { input: 1.25, output: 10 },
1230
- "gemini-2.5-flash": { input: 0.3, output: 2.5 },
1231
- // OpenAI flagship text models (verified 2026-05-21, standard short-context tier)
1232
- "gpt-5.5": { input: 5, output: 30 },
1233
- "gpt-5.5-pro": { input: 30, output: 180 },
1234
- "gpt-5.4": { input: 2.5, output: 15 },
1235
- "gpt-5.4-mini": { input: 0.75, output: 4.5 },
1236
- "gpt-5.4-nano": { input: 0.2, output: 1.25 },
1237
- "gpt-5.4-pro": { input: 30, output: 180 },
1238
- "gpt-4o-mini": { input: 0.15, output: 0.6 },
1239
- "gpt-4o": { input: 2.5, output: 10 },
1240
- "gpt-4.1-mini": { input: 0.4, output: 1.6 },
1241
- "gpt-4.1-nano": { input: 0.1, output: 0.4 },
1242
- "gpt-4.1": { input: 2, output: 8 },
1243
- // DeepSeek (verified 2026-05-05; legacy names map to v4-flash per vendor)
1244
- "deepseek-chat": { input: 0.14, output: 0.28 },
1245
- "deepseek-reasoner": { input: 0.14, output: 0.28 },
1246
- "deepseek-v4-flash": { input: 0.14, output: 0.28 }
1247
- };
1248
- var LLM_PRICING_FAMILY_RATES = [
1249
- { match: /^gemini-2\.5-pro/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gemini-2.5-pro"] },
1250
- { match: /^gemini-2\.5-flash/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gemini-2.5-flash"] },
1251
- { match: /^gpt-5\.5-pro/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gpt-5.5-pro"] },
1252
- { match: /^gpt-5\.5/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gpt-5.5"] },
1253
- { match: /^gpt-5\.4-pro/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gpt-5.4-pro"] },
1254
- { match: /^gpt-5\.4-mini/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gpt-5.4-mini"] },
1255
- { match: /^gpt-5\.4-nano/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gpt-5.4-nano"] },
1256
- { match: /^gpt-5\.4/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gpt-5.4"] },
1257
- { match: /^gpt-4o-mini/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gpt-4o-mini"] },
1258
- { match: /^gpt-4o(?!-mini)/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gpt-4o"] },
1259
- { match: /^gpt-4\.1-mini/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gpt-4.1-mini"] },
1260
- { match: /^gpt-4\.1-nano/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gpt-4.1-nano"] },
1261
- { match: /^gpt-4\.1(?!-mini|-nano)/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gpt-4.1"] },
1262
- // Anthropic Claude 4.x list prices (verified 2026): Opus $5/$25, Sonnet
1263
- // $3/$15, Haiku 4.5 $1/$5 per 1M tokens (input/output).
1264
- { match: /^claude-opus-/i, rate: { input: 5, output: 25 } },
1265
- { match: /^claude-haiku-/i, rate: { input: 1, output: 5 } },
1266
- { match: /^claude-sonnet-/i, rate: { input: 3, output: 15 } },
1267
- { match: /^opus-/i, rate: { input: 5, output: 25 } },
1268
- { match: /^haiku-/i, rate: { input: 1, output: 5 } },
1269
- { match: /^sonnet-/i, rate: { input: 3, output: 15 } },
1270
- { match: /^deepseek-chat/i, rate: LLM_PRICING_USD_PER_M_TOKENS["deepseek-chat"] },
1271
- { match: /^deepseek-reasoner/i, rate: LLM_PRICING_USD_PER_M_TOKENS["deepseek-reasoner"] },
1272
- { match: /^deepseek-v4-flash/i, rate: LLM_PRICING_USD_PER_M_TOKENS["deepseek-v4-flash"] }
1273
- ];
1274
-
1275
- // ../node-auth/src/clone-entitlements.ts
1276
- var ENTITLED_CLONE_SET = new Set(ALL_ENTITLED_CLONES);
1114
+ // ../node-auth/src/credential-store.ts
1115
+ function errorMessage2(error) {
1116
+ return error instanceof Error ? error.message : String(error);
1117
+ }
1118
+ var ENTITLED_CLONE_SET = new Set(ALL_STARTABLE_CLONE_IDS);
1277
1119
  function normalizeEntitledCloneIds(cloneIds) {
1278
1120
  if (!cloneIds) {
1279
1121
  return [];
@@ -1290,8 +1132,6 @@ function normalizeEntitledCloneIds(cloneIds) {
1290
1132
  }
1291
1133
  return [...normalized];
1292
1134
  }
1293
-
1294
- // ../node-auth/src/credential-store.ts
1295
1135
  var KEYCHAIN_COMMAND_TIMEOUT_MS = 1500;
1296
1136
  var ARCHAL_DIR_NAME = ".archal";
1297
1137
  var TEST_SANDBOX_ID_ENV_VAR = "ARCHAL_TEST_SANDBOX_ID";
@@ -1363,7 +1203,7 @@ function seedSandboxFromRealHomeOnce(sandboxDir) {
1363
1203
  }
1364
1204
  }
1365
1205
  function getArchalDir() {
1366
- const explicit = process.env["ARCHAL_HOME"];
1206
+ const explicit = process.env["ARCHAL_HOME"]?.trim();
1367
1207
  if (explicit) {
1368
1208
  return explicit;
1369
1209
  }
@@ -1647,7 +1487,66 @@ function readCredentialsFile(options) {
1647
1487
  return readCredentialsFileAtPath(getCredentialsPath(), options);
1648
1488
  }
1649
1489
  function isWorkspaceApiKey(token) {
1650
- return token.startsWith("archal_ws_") || token.startsWith("archal_") && !token.includes(".");
1490
+ return token.startsWith(WORKSPACE_API_KEY_PREFIX) || token.startsWith("archal_") && !token.includes(".");
1491
+ }
1492
+ var WORKSPACE_API_KEY_EXPIRES_SECONDS = 365 * 24 * 60 * 60;
1493
+ function parseEnvToken(token, envName = AUTH_TOKEN_ENV_VAR, nowSeconds = Math.floor(Date.now() / 1e3)) {
1494
+ const trimmed = token.trim();
1495
+ if (!trimmed) {
1496
+ return { status: "invalid", message: `${envName} is empty.` };
1497
+ }
1498
+ if (isWorkspaceApiKey(trimmed)) {
1499
+ return {
1500
+ status: "ok",
1501
+ credentials: {
1502
+ token: trimmed,
1503
+ refreshToken: "",
1504
+ email: "(workspace-api-key)",
1505
+ plan: "pro",
1506
+ selectedCloneIds: [],
1507
+ expiresAt: nowSeconds + WORKSPACE_API_KEY_EXPIRES_SECONDS
1508
+ }
1509
+ };
1510
+ }
1511
+ const claims = decodeJwtPayload(trimmed);
1512
+ if (claims === null) {
1513
+ return {
1514
+ status: "invalid",
1515
+ message: `${envName} must be a JWT with valid plan and exp claims or a workspace API key (archal_ws_...).`
1516
+ };
1517
+ }
1518
+ const email = typeof claims["email"] === "string" ? claims["email"] : `(from ${envName})`;
1519
+ if (!isPlan(claims["plan"])) {
1520
+ return {
1521
+ status: "invalid",
1522
+ message: `${envName} JWT does not contain a valid plan claim.`
1523
+ };
1524
+ }
1525
+ const plan = claims["plan"];
1526
+ if (typeof claims["exp"] !== "number" || !Number.isFinite(claims["exp"])) {
1527
+ return {
1528
+ status: "invalid",
1529
+ message: `${envName} JWT does not contain a valid exp claim.`
1530
+ };
1531
+ }
1532
+ const expiresAt = claims["exp"];
1533
+ if (expiresAt <= nowSeconds) {
1534
+ return {
1535
+ status: "expired",
1536
+ message: `${envName} is expired. Remove it or replace it with a valid token.`
1537
+ };
1538
+ }
1539
+ return {
1540
+ status: "ok",
1541
+ credentials: {
1542
+ token: trimmed,
1543
+ refreshToken: "",
1544
+ email,
1545
+ plan,
1546
+ selectedCloneIds: [],
1547
+ expiresAt
1548
+ }
1549
+ };
1651
1550
  }
1652
1551
  function getStoredCredentials(options) {
1653
1552
  const creds = readCredentialsFile(options);
@@ -1804,8 +1703,37 @@ function getConfiguredAuthBaseUrl(options) {
1804
1703
  }
1805
1704
  return isStrictEndpointModeEnabled() ? null : HOSTED_DEFAULT_AUTH_BASE_URL;
1806
1705
  }
1706
+ function readConfiguredUrlFromEnvChain(envVarNames, options) {
1707
+ const uniqueEnvVars = [...new Set(envVarNames)];
1708
+ return readConfiguredUrl(options, ...uniqueEnvVars);
1709
+ }
1710
+ function getConfiguredAuthValidationBaseUrl(options = {}) {
1711
+ const apiUrlEnvVar = options.apiUrlEnvVar ?? "ARCHAL_API_URL";
1712
+ const authUrlEnvVar = options.authUrlEnvVar ?? "ARCHAL_AUTH_URL";
1713
+ const resolved = readConfiguredUrlFromEnvChain([
1714
+ apiUrlEnvVar,
1715
+ authUrlEnvVar,
1716
+ "ARCHAL_AUTH_URL",
1717
+ "ARCHAL_AUTH_BASE_URL",
1718
+ "ARCHAL_API_URL",
1719
+ "ARCHAL_API_BASE_URL"
1720
+ ], options);
1721
+ if (resolved) {
1722
+ return resolved;
1723
+ }
1724
+ return isStrictEndpointModeEnabled() ? null : HOSTED_DEFAULT_AUTH_BASE_URL;
1725
+ }
1726
+ function getConfiguredVitestApiBaseUrl(fallback = HOSTED_DEFAULT_API_BASE_URL, options) {
1727
+ return readConfiguredUrlFromEnvChain([
1728
+ "ARCHAL_VITEST_API_URL",
1729
+ "ARCHAL_API_URL",
1730
+ "ARCHAL_API_BASE_URL",
1731
+ "ARCHAL_AUTH_URL",
1732
+ "ARCHAL_AUTH_BASE_URL"
1733
+ ], options) ?? fallback;
1734
+ }
1807
1735
 
1808
- // ../node-auth/src/request-metadata.ts
1736
+ // ../node-auth/src/token-exchange.ts
1809
1737
  function buildAuthRequestHeaders(metadata, includeContentType = false) {
1810
1738
  const headers = {};
1811
1739
  if (includeContentType) {
@@ -1933,34 +1861,6 @@ import { createHash as createHash2, timingSafeEqual } from "crypto";
1933
1861
  var STORED_CREDENTIALS_LOCK_TIMEOUT_MS = 3e4;
1934
1862
  var STORED_CREDENTIALS_STALE_LOCK_MS = STORED_CREDENTIALS_LOCK_TIMEOUT_MS;
1935
1863
  var STORED_CREDENTIALS_LOCK_POLL_INTERVAL_MS = 50;
1936
- var DEFAULT_AUTH_BASE_URL = "https://www.archal.ai";
1937
- var WORKSPACE_API_KEY_EXPIRES_SECONDS = 365 * 24 * 60 * 60;
1938
- function readFirstConfiguredBaseUrl(envVars) {
1939
- for (const envVar of envVars) {
1940
- const configured = trimEnv(envVar);
1941
- if (!configured) {
1942
- continue;
1943
- }
1944
- const normalized = normalizeApiBaseUrl(configured);
1945
- if (normalized) {
1946
- return normalized;
1947
- }
1948
- }
1949
- return null;
1950
- }
1951
- function resolveHostedAuthBaseUrl(options) {
1952
- const authUrlEnvVar = options.authUrlEnvVar ?? "ARCHAL_AUTH_URL";
1953
- const apiUrlEnvVar = options.apiUrlEnvVar ?? "ARCHAL_API_URL";
1954
- const envVars = [.../* @__PURE__ */ new Set([
1955
- apiUrlEnvVar,
1956
- authUrlEnvVar,
1957
- "ARCHAL_AUTH_URL",
1958
- "ARCHAL_AUTH_BASE_URL",
1959
- "ARCHAL_API_URL",
1960
- "ARCHAL_API_BASE_URL"
1961
- ])];
1962
- return readFirstConfiguredBaseUrl(envVars) ?? DEFAULT_AUTH_BASE_URL;
1963
- }
1964
1864
  function isImplicitTestSandboxFlow() {
1965
1865
  if (trimEnv("ARCHAL_HOME")) {
1966
1866
  return false;
@@ -1977,59 +1877,11 @@ function readExplicitEnvCredentials(envName) {
1977
1877
  if (!token) {
1978
1878
  return { kind: "missing" };
1979
1879
  }
1980
- const claims = decodeJwtPayload(token);
1981
- const nowSeconds = Math.floor(Date.now() / 1e3);
1982
- if (claims === null) {
1983
- if (isWorkspaceApiKey(token)) {
1984
- return {
1985
- kind: "valid",
1986
- credentials: {
1987
- token,
1988
- refreshToken: "",
1989
- email: "(workspace-api-key)",
1990
- plan: "pro",
1991
- selectedCloneIds: [],
1992
- expiresAt: nowSeconds + WORKSPACE_API_KEY_EXPIRES_SECONDS
1993
- }
1994
- };
1995
- }
1996
- return {
1997
- kind: "invalid",
1998
- message: `${envName} must be a JWT with valid plan and exp claims or a workspace API key (archal_ws_...).`
1999
- };
2000
- }
2001
- const email = typeof claims["email"] === "string" ? claims["email"] : `(from ${envName})`;
2002
- if (!isPlan(claims["plan"])) {
2003
- return {
2004
- kind: "invalid",
2005
- message: `${envName} JWT does not contain a valid plan claim.`
2006
- };
2007
- }
2008
- const plan = claims["plan"];
2009
- if (typeof claims["exp"] !== "number" || !Number.isFinite(claims["exp"])) {
2010
- return {
2011
- kind: "invalid",
2012
- message: `${envName} JWT does not contain a valid exp claim.`
2013
- };
2014
- }
2015
- const expiresAt = claims["exp"];
2016
- if (expiresAt <= nowSeconds) {
2017
- return {
2018
- kind: "invalid",
2019
- message: `${envName} is expired. Remove it or replace it with a valid token.`
2020
- };
1880
+ const parsed = parseEnvToken(token, envName);
1881
+ if (parsed.status !== "ok") {
1882
+ return { kind: "invalid", message: parsed.message };
2021
1883
  }
2022
- return {
2023
- kind: "valid",
2024
- credentials: {
2025
- token,
2026
- refreshToken: "",
2027
- email,
2028
- plan,
2029
- selectedCloneIds: [],
2030
- expiresAt
2031
- }
2032
- };
1884
+ return { kind: "valid", credentials: parsed.credentials };
2033
1885
  }
2034
1886
  function readStoredCredentials(includeExpired = false) {
2035
1887
  prepareStoredCredentialSources();
@@ -2061,16 +1913,6 @@ function resolveCredentialsWithSource(tokenEnvVar, includeExpiredStored = false)
2061
1913
  }
2062
1914
  return { credentials: storedCredentials, source: "stored" };
2063
1915
  }
2064
- function resolveHostedCredentials(tokenEnvVar = "ARCHAL_TOKEN") {
2065
- return resolveCredentialsWithSource(tokenEnvVar)?.credentials ?? null;
2066
- }
2067
- function getCredentials2(tokenEnvVar = "ARCHAL_TOKEN") {
2068
- const credentials = resolveHostedCredentials(tokenEnvVar);
2069
- if (!credentials) {
2070
- return null;
2071
- }
2072
- return credentials.expiresAt > Math.floor(Date.now() / 1e3) ? credentials : null;
2073
- }
2074
1916
  function prepareStoredCredentialSources() {
2075
1917
  if (isImplicitTestSandboxFlow()) {
2076
1918
  seedTestSandboxCredentialsFromRealHome();
@@ -2156,7 +1998,15 @@ async function resolveCurrentCredentials(credentials, source, forceValidation, a
2156
1998
  }
2157
1999
  async function createHostedAuthLease(options = {}) {
2158
2000
  const tokenEnvVar = options.tokenEnvVar ?? "ARCHAL_TOKEN";
2159
- const authBaseUrl = resolveHostedAuthBaseUrl(options);
2001
+ const authBaseUrl = getConfiguredAuthValidationBaseUrl({
2002
+ apiUrlEnvVar: options.apiUrlEnvVar,
2003
+ authUrlEnvVar: options.authUrlEnvVar
2004
+ });
2005
+ if (!authBaseUrl) {
2006
+ throw new Error(
2007
+ "Hosted auth validation requires ARCHAL_AUTH_URL or ARCHAL_API_URL when ARCHAL_STRICT_ENDPOINTS=1."
2008
+ );
2009
+ }
2160
2010
  const resolved = resolveCredentialsWithSource(tokenEnvVar, true);
2161
2011
  if (!resolved) {
2162
2012
  const tokenSources = Array.from(/* @__PURE__ */ new Set([tokenEnvVar, "ARCHAL_TOKEN"])).join(", ");
@@ -2739,6 +2589,7 @@ function positiveIntegerFromEnv(name, fallback) {
2739
2589
  }
2740
2590
 
2741
2591
  export {
2592
+ getConfiguredVitestApiBaseUrl,
2742
2593
  sleep,
2743
2594
  DEFAULT_HOSTED_API_BASE_URL,
2744
2595
  DEFAULT_SESSION_TTL_SECONDS,
@@ -2748,11 +2599,9 @@ export {
2748
2599
  MIN_READY_TIMEOUT_MS,
2749
2600
  trimEnv,
2750
2601
  parsePositiveInteger,
2751
- normalizeApiBaseUrl,
2752
2602
  fileExists,
2753
2603
  requestedSeedsMatchSession,
2754
2604
  HostedSessionClient,
2755
- getCredentials2 as getCredentials,
2756
2605
  createHostedAuthLease,
2757
2606
  getSessionIdFilePath,
2758
2607
  loadFileSeedsIntoClones,