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
@@ -14,6 +14,7 @@ var CREDENTIALS_MASTER_KEY_ENV_VAR = "ARCHAL_CREDENTIALS_MASTER_KEY";
14
14
  var KEYCHAIN_SERVICE = "archal-cli";
15
15
  var KEYCHAIN_ACCOUNT = "credentials-master-key";
16
16
  var HOSTED_DEFAULT_AUTH_BASE_URL = "https://www.archal.ai";
17
+ var WORKSPACE_API_KEY_PREFIX = "archal_ws_";
17
18
  var STRICT_ENDPOINTS_ENV_VAR = "ARCHAL_STRICT_ENDPOINTS";
18
19
  var REQUEST_TIMEOUT_MS = 8e3;
19
20
  var ENV_TOKEN_FALLBACK_TTL_SECONDS = 24 * 60 * 60;
@@ -23,11 +24,6 @@ function isPlan(value) {
23
24
  return value === "free" || value === "pro" || value === "enterprise";
24
25
  }
25
26
 
26
- // ../node-auth/src/errors.ts
27
- function errorMessage(error) {
28
- return error instanceof Error ? error.message : String(error);
29
- }
30
-
31
27
  // ../node-auth/src/credential-store.ts
32
28
  var import_node_child_process = require("child_process");
33
29
  var import_node_crypto = require("crypto");
@@ -60,7 +56,7 @@ var GENERATED_CLONE_CATALOG = [
60
56
  name: "Cal.com",
61
57
  description: "Event types, schedules, availability slots, bookings, calendars, and webhooks.",
62
58
  stage: "preview",
63
- toolCount: 18,
59
+ toolCount: 35,
64
60
  transport: "both",
65
61
  architectureClass: "domain-simulator",
66
62
  domainPrimitives: [
@@ -78,7 +74,7 @@ var GENERATED_CLONE_CATALOG = [
78
74
  name: "ClickUp",
79
75
  description: "Teams, spaces, folders, lists, tasks, comments, tags, time tracking, and checklists.",
80
76
  stage: "preview",
81
- toolCount: 40,
77
+ toolCount: 123,
82
78
  transport: "both",
83
79
  architectureClass: "standard-core",
84
80
  domainPrimitives: [],
@@ -91,7 +87,7 @@ var GENERATED_CLONE_CATALOG = [
91
87
  name: "Customer.io",
92
88
  description: "Messaging automation across campaigns, broadcasts, transactional email, segments, customers, and message delivery.",
93
89
  stage: "preview",
94
- toolCount: 22,
90
+ toolCount: 129,
95
91
  transport: "rest",
96
92
  architectureClass: "standard-core",
97
93
  domainPrimitives: [],
@@ -156,7 +152,7 @@ var GENERATED_CLONE_CATALOG = [
156
152
  name: "GitLab",
157
153
  description: "Projects, branches, commits, issues, merge requests, pipelines, labels, milestones, releases, and webhooks.",
158
154
  stage: "preview",
159
- toolCount: 46,
155
+ toolCount: 559,
160
156
  transport: "both",
161
157
  architectureClass: "domain-simulator",
162
158
  domainPrimitives: [
@@ -191,7 +187,7 @@ var GENERATED_CLONE_CATALOG = [
191
187
  name: "HubSpot",
192
188
  description: "CRM contacts, companies, deals, tickets, and engagements.",
193
189
  stage: "preview",
194
- toolCount: 41,
190
+ toolCount: 44,
195
191
  transport: "rest",
196
192
  architectureClass: "replay-shell",
197
193
  domainPrimitives: [
@@ -226,7 +222,7 @@ var GENERATED_CLONE_CATALOG = [
226
222
  name: "Linear",
227
223
  description: "Issues, projects, teams, cycles, and workflows.",
228
224
  stage: "public",
229
- toolCount: 50,
225
+ toolCount: 53,
230
226
  transport: "both",
231
227
  architectureClass: "domain-simulator",
232
228
  domainPrimitives: [
@@ -295,7 +291,7 @@ var GENERATED_CLONE_CATALOG = [
295
291
  name: "Sentry",
296
292
  description: "Error monitoring across organizations, projects, teams, issues, events, releases, and DSN keys.",
297
293
  stage: "preview",
298
- toolCount: 25,
294
+ toolCount: 34,
299
295
  transport: "rest",
300
296
  architectureClass: "domain-simulator",
301
297
  domainPrimitives: [
@@ -397,14 +393,10 @@ var GENERATED_CLONE_CATALOG = [
397
393
  name: "Webflow",
398
394
  description: "Sites, pages, CMS collections, items, assets, forms, and webhooks.",
399
395
  stage: "preview",
400
- toolCount: 19,
401
- transport: "rest",
402
- architectureClass: "replay-shell",
403
- domainPrimitives: [
404
- "recording replay cursor",
405
- "CMS collection/item overlays",
406
- "publish lifecycle captures"
407
- ],
396
+ toolCount: 104,
397
+ transport: "both",
398
+ architectureClass: "standard-core",
399
+ domainPrimitives: [],
408
400
  behaviorOwner: null,
409
401
  opsCoverage: 100
410
402
  }
@@ -500,142 +492,11 @@ var STARTABLE_CLONE_CATALOG = CLONE_CATALOG.filter(
500
492
  (entry) => STARTABLE_CLONE_ID_SET.has(entry.id)
501
493
  );
502
494
 
503
- // ../billing-constants/src/credit-catalog.ts
504
- var CREDIT_COGS_MARKUP = 3;
505
- var CREDIT_TARGET_GROSS_MARGIN_PERCENT = Math.round(
506
- (1 - 1 / CREDIT_COGS_MARKUP) * 100
507
- );
508
-
509
- // ../billing-constants/src/index.ts
510
- var PLAN_MONTHLY_TWIN_MINUTE_LIMITS = {
511
- free: 500,
512
- pro: 5e3,
513
- enterprise: null
514
- };
515
- var PLAN_CONCURRENT_SESSION_LIMITS = {
516
- free: 3,
517
- pro: 10,
518
- enterprise: 50
519
- };
520
- var FREE_WORKSPACE_MEMBER_LIMIT = 2;
521
- var PRO_PLAN_PRICE_USD = 199;
522
- function formatMinutesLabel(minutes) {
523
- return minutes.toLocaleString("en-US");
524
- }
525
- var FREE_MINUTES = PLAN_MONTHLY_TWIN_MINUTE_LIMITS.free;
526
- var PRO_MINUTES = PLAN_MONTHLY_TWIN_MINUTE_LIMITS.pro;
527
- if (FREE_MINUTES == null || PRO_MINUTES == null) {
528
- throw new Error("PLAN_MONTHLY_TWIN_MINUTE_LIMITS: free and pro must be non-null");
529
- }
530
- var PRO_EVALS_PER_SEAT = 500;
531
- var PRO_SESSION_MINUTES_PER_SEAT = 5e3;
532
- var PRO_MAX_SEATS = 5;
533
- var FREE_EVALS_PER_MONTH = 100;
534
- var PLAN_DISPLAY = {
535
- free: {
536
- tag: "Free",
537
- priceLabel: "$0",
538
- periodLabel: "",
539
- included: [
540
- `${formatMinutesLabel(FREE_MINUTES)} session-minutes / account`,
541
- `${FREE_EVALS_PER_MONTH} evals / account`,
542
- `1 workspace (${FREE_WORKSPACE_MEMBER_LIMIT} users max)`,
543
- `${PLAN_CONCURRENT_SESSION_LIMITS.free} concurrent sessions / workspace`,
544
- "All clones included"
545
- ]
546
- },
547
- pro: {
548
- tag: "Pro",
549
- priceLabel: `$${PRO_PLAN_PRICE_USD}`,
550
- periodLabel: "/mo per seat",
551
- included: [
552
- `${formatMinutesLabel(PRO_SESSION_MINUTES_PER_SEAT)} session-minutes / seat / month`,
553
- `${PRO_EVALS_PER_SEAT} evals / seat / month`,
554
- "All clones included",
555
- `${PLAN_CONCURRENT_SESSION_LIMITS.pro} concurrent sessions / workspace`,
556
- `1 workspace, up to ${PRO_MAX_SEATS} seats with pooled usage`
557
- ]
558
- },
559
- enterprise: {
560
- tag: "Enterprise",
561
- priceLabel: "Contact us",
562
- periodLabel: "",
563
- included: [
564
- "Unlimited session-minutes",
565
- "Unlimited seats per workspace",
566
- "Unlimited workspaces",
567
- `${PLAN_CONCURRENT_SESSION_LIMITS.enterprise} concurrent sessions / workspace`,
568
- "SSO / SAML",
569
- "SOC 2 (in progress)",
570
- "Custom clones & eval support",
571
- "Dedicated onboarding & support"
572
- ]
573
- }
574
- };
575
- var PLAN_MAX_SESSION_TTL_SECONDS = {
576
- free: 30 * 60,
577
- // 30 minutes
578
- pro: 60 * 60,
579
- // 60 minutes
580
- enterprise: 90 * 60
581
- // 90 minutes
582
- };
583
- var MAX_ABSOLUTE_SESSION_LIFETIME_SECONDS = 4 * 60 * 60;
584
- var LIFETIME_PERIOD_RESETS_AT = new Date(Date.UTC(9999, 11, 31));
585
- var ALL_ENTITLED_CLONES = ALL_STARTABLE_CLONE_IDS;
586
- var SCENARIO_USAGE_WINDOW_DAYS = 7;
587
- var SCENARIO_USAGE_WINDOW_MS = SCENARIO_USAGE_WINDOW_DAYS * 24 * 60 * 60 * 1e3;
588
- var SCENARIO_USAGE_WINDOW_SECONDS = SCENARIO_USAGE_WINDOW_DAYS * 24 * 60 * 60;
589
- var LLM_PRICING_USD_PER_M_TOKENS = {
590
- // Google Gemini (verified 2026-05-05, standard tier <=200K input tokens)
591
- "gemini-2.5-pro": { input: 1.25, output: 10 },
592
- "gemini-2.5-flash": { input: 0.3, output: 2.5 },
593
- // OpenAI flagship text models (verified 2026-05-21, standard short-context tier)
594
- "gpt-5.5": { input: 5, output: 30 },
595
- "gpt-5.5-pro": { input: 30, output: 180 },
596
- "gpt-5.4": { input: 2.5, output: 15 },
597
- "gpt-5.4-mini": { input: 0.75, output: 4.5 },
598
- "gpt-5.4-nano": { input: 0.2, output: 1.25 },
599
- "gpt-5.4-pro": { input: 30, output: 180 },
600
- "gpt-4o-mini": { input: 0.15, output: 0.6 },
601
- "gpt-4o": { input: 2.5, output: 10 },
602
- "gpt-4.1-mini": { input: 0.4, output: 1.6 },
603
- "gpt-4.1-nano": { input: 0.1, output: 0.4 },
604
- "gpt-4.1": { input: 2, output: 8 },
605
- // DeepSeek (verified 2026-05-05; legacy names map to v4-flash per vendor)
606
- "deepseek-chat": { input: 0.14, output: 0.28 },
607
- "deepseek-reasoner": { input: 0.14, output: 0.28 },
608
- "deepseek-v4-flash": { input: 0.14, output: 0.28 }
609
- };
610
- var LLM_PRICING_FAMILY_RATES = [
611
- { match: /^gemini-2\.5-pro/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gemini-2.5-pro"] },
612
- { match: /^gemini-2\.5-flash/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gemini-2.5-flash"] },
613
- { match: /^gpt-5\.5-pro/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gpt-5.5-pro"] },
614
- { match: /^gpt-5\.5/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gpt-5.5"] },
615
- { match: /^gpt-5\.4-pro/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gpt-5.4-pro"] },
616
- { match: /^gpt-5\.4-mini/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gpt-5.4-mini"] },
617
- { match: /^gpt-5\.4-nano/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gpt-5.4-nano"] },
618
- { match: /^gpt-5\.4/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gpt-5.4"] },
619
- { match: /^gpt-4o-mini/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gpt-4o-mini"] },
620
- { match: /^gpt-4o(?!-mini)/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gpt-4o"] },
621
- { match: /^gpt-4\.1-mini/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gpt-4.1-mini"] },
622
- { match: /^gpt-4\.1-nano/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gpt-4.1-nano"] },
623
- { match: /^gpt-4\.1(?!-mini|-nano)/i, rate: LLM_PRICING_USD_PER_M_TOKENS["gpt-4.1"] },
624
- // Anthropic Claude 4.x list prices (verified 2026): Opus $5/$25, Sonnet
625
- // $3/$15, Haiku 4.5 $1/$5 per 1M tokens (input/output).
626
- { match: /^claude-opus-/i, rate: { input: 5, output: 25 } },
627
- { match: /^claude-haiku-/i, rate: { input: 1, output: 5 } },
628
- { match: /^claude-sonnet-/i, rate: { input: 3, output: 15 } },
629
- { match: /^opus-/i, rate: { input: 5, output: 25 } },
630
- { match: /^haiku-/i, rate: { input: 1, output: 5 } },
631
- { match: /^sonnet-/i, rate: { input: 3, output: 15 } },
632
- { match: /^deepseek-chat/i, rate: LLM_PRICING_USD_PER_M_TOKENS["deepseek-chat"] },
633
- { match: /^deepseek-reasoner/i, rate: LLM_PRICING_USD_PER_M_TOKENS["deepseek-reasoner"] },
634
- { match: /^deepseek-v4-flash/i, rate: LLM_PRICING_USD_PER_M_TOKENS["deepseek-v4-flash"] }
635
- ];
636
-
637
- // ../node-auth/src/clone-entitlements.ts
638
- var ENTITLED_CLONE_SET = new Set(ALL_ENTITLED_CLONES);
495
+ // ../node-auth/src/credential-store.ts
496
+ function errorMessage(error) {
497
+ return error instanceof Error ? error.message : String(error);
498
+ }
499
+ var ENTITLED_CLONE_SET = new Set(ALL_STARTABLE_CLONE_IDS);
639
500
  function normalizeEntitledCloneIds(cloneIds) {
640
501
  if (!cloneIds) {
641
502
  return [];
@@ -652,8 +513,6 @@ function normalizeEntitledCloneIds(cloneIds) {
652
513
  }
653
514
  return [...normalized];
654
515
  }
655
-
656
- // ../node-auth/src/credential-store.ts
657
516
  var KEYCHAIN_COMMAND_TIMEOUT_MS = 1500;
658
517
  var ARCHAL_DIR_NAME = ".archal";
659
518
  var TEST_SANDBOX_ID_ENV_VAR = "ARCHAL_TEST_SANDBOX_ID";
@@ -725,7 +584,7 @@ function seedSandboxFromRealHomeOnce(sandboxDir) {
725
584
  }
726
585
  }
727
586
  function getArchalDir() {
728
- const explicit = process.env["ARCHAL_HOME"];
587
+ const explicit = process.env["ARCHAL_HOME"]?.trim();
729
588
  if (explicit) {
730
589
  return explicit;
731
590
  }
@@ -1009,7 +868,66 @@ function readCredentialsFile(options) {
1009
868
  return readCredentialsFileAtPath(getCredentialsPath(), options);
1010
869
  }
1011
870
  function isWorkspaceApiKey(token) {
1012
- return token.startsWith("archal_ws_") || token.startsWith("archal_") && !token.includes(".");
871
+ return token.startsWith(WORKSPACE_API_KEY_PREFIX) || token.startsWith("archal_") && !token.includes(".");
872
+ }
873
+ var WORKSPACE_API_KEY_EXPIRES_SECONDS = 365 * 24 * 60 * 60;
874
+ function parseEnvToken(token, envName = AUTH_TOKEN_ENV_VAR, nowSeconds = Math.floor(Date.now() / 1e3)) {
875
+ const trimmed = token.trim();
876
+ if (!trimmed) {
877
+ return { status: "invalid", message: `${envName} is empty.` };
878
+ }
879
+ if (isWorkspaceApiKey(trimmed)) {
880
+ return {
881
+ status: "ok",
882
+ credentials: {
883
+ token: trimmed,
884
+ refreshToken: "",
885
+ email: "(workspace-api-key)",
886
+ plan: "pro",
887
+ selectedCloneIds: [],
888
+ expiresAt: nowSeconds + WORKSPACE_API_KEY_EXPIRES_SECONDS
889
+ }
890
+ };
891
+ }
892
+ const claims = decodeJwtPayload(trimmed);
893
+ if (claims === null) {
894
+ return {
895
+ status: "invalid",
896
+ message: `${envName} must be a JWT with valid plan and exp claims or a workspace API key (archal_ws_...).`
897
+ };
898
+ }
899
+ const email = typeof claims["email"] === "string" ? claims["email"] : `(from ${envName})`;
900
+ if (!isPlan(claims["plan"])) {
901
+ return {
902
+ status: "invalid",
903
+ message: `${envName} JWT does not contain a valid plan claim.`
904
+ };
905
+ }
906
+ const plan = claims["plan"];
907
+ if (typeof claims["exp"] !== "number" || !Number.isFinite(claims["exp"])) {
908
+ return {
909
+ status: "invalid",
910
+ message: `${envName} JWT does not contain a valid exp claim.`
911
+ };
912
+ }
913
+ const expiresAt = claims["exp"];
914
+ if (expiresAt <= nowSeconds) {
915
+ return {
916
+ status: "expired",
917
+ message: `${envName} is expired. Remove it or replace it with a valid token.`
918
+ };
919
+ }
920
+ return {
921
+ status: "ok",
922
+ credentials: {
923
+ token: trimmed,
924
+ refreshToken: "",
925
+ email,
926
+ plan,
927
+ selectedCloneIds: [],
928
+ expiresAt
929
+ }
930
+ };
1013
931
  }
1014
932
  function getStoredCredentials(options) {
1015
933
  const creds = readCredentialsFile(options);
@@ -1166,8 +1084,59 @@ function getConfiguredAuthBaseUrl(options) {
1166
1084
  }
1167
1085
  return isStrictEndpointModeEnabled() ? null : HOSTED_DEFAULT_AUTH_BASE_URL;
1168
1086
  }
1087
+ function readConfiguredUrlFromEnvChain(envVarNames, options) {
1088
+ const uniqueEnvVars = [...new Set(envVarNames)];
1089
+ return readConfiguredUrl(options, ...uniqueEnvVars);
1090
+ }
1091
+ function getConfiguredAuthValidationBaseUrl(options = {}) {
1092
+ const apiUrlEnvVar = options.apiUrlEnvVar ?? "ARCHAL_API_URL";
1093
+ const authUrlEnvVar = options.authUrlEnvVar ?? "ARCHAL_AUTH_URL";
1094
+ const resolved = readConfiguredUrlFromEnvChain([
1095
+ apiUrlEnvVar,
1096
+ authUrlEnvVar,
1097
+ "ARCHAL_AUTH_URL",
1098
+ "ARCHAL_AUTH_BASE_URL",
1099
+ "ARCHAL_API_URL",
1100
+ "ARCHAL_API_BASE_URL"
1101
+ ], options);
1102
+ if (resolved) {
1103
+ return resolved;
1104
+ }
1105
+ return isStrictEndpointModeEnabled() ? null : HOSTED_DEFAULT_AUTH_BASE_URL;
1106
+ }
1107
+
1108
+ // ../retry/dist/index.js
1109
+ function abortReason(signal) {
1110
+ return signal.reason instanceof Error ? signal.reason : new DOMException("The operation was aborted.", "AbortError");
1111
+ }
1112
+ function sleep(ms, options) {
1113
+ const signal = options?.signal;
1114
+ if (signal?.aborted) {
1115
+ return Promise.reject(abortReason(signal));
1116
+ }
1117
+ if (ms <= 0) {
1118
+ return Promise.resolve();
1119
+ }
1120
+ if (!signal) {
1121
+ return new Promise((resolve) => {
1122
+ setTimeout(resolve, ms);
1123
+ });
1124
+ }
1125
+ const abortSignal = signal;
1126
+ return new Promise((resolve, reject) => {
1127
+ const timeout = setTimeout(() => {
1128
+ abortSignal.removeEventListener("abort", onAbort);
1129
+ resolve();
1130
+ }, ms);
1131
+ function onAbort() {
1132
+ clearTimeout(timeout);
1133
+ reject(abortReason(abortSignal));
1134
+ }
1135
+ abortSignal.addEventListener("abort", onAbort, { once: true });
1136
+ });
1137
+ }
1169
1138
 
1170
- // ../node-auth/src/request-metadata.ts
1139
+ // ../node-auth/src/token-exchange.ts
1171
1140
  function buildAuthRequestHeaders(metadata, includeContentType = false) {
1172
1141
  const headers = {};
1173
1142
  if (includeContentType) {
@@ -1288,37 +1257,6 @@ async function validateAuthWithServerResult(creds, metadata) {
1288
1257
  };
1289
1258
  }
1290
1259
 
1291
- // ../retry/dist/index.js
1292
- function abortReason(signal) {
1293
- return signal.reason instanceof Error ? signal.reason : new DOMException("The operation was aborted.", "AbortError");
1294
- }
1295
- function sleep(ms, options) {
1296
- const signal = options?.signal;
1297
- if (signal?.aborted) {
1298
- return Promise.reject(abortReason(signal));
1299
- }
1300
- if (ms <= 0) {
1301
- return Promise.resolve();
1302
- }
1303
- if (!signal) {
1304
- return new Promise((resolve) => {
1305
- setTimeout(resolve, ms);
1306
- });
1307
- }
1308
- const abortSignal = signal;
1309
- return new Promise((resolve, reject) => {
1310
- const timeout = setTimeout(() => {
1311
- abortSignal.removeEventListener("abort", onAbort);
1312
- resolve();
1313
- }, ms);
1314
- function onAbort() {
1315
- clearTimeout(timeout);
1316
- reject(abortReason(abortSignal));
1317
- }
1318
- abortSignal.addEventListener("abort", onAbort, { once: true });
1319
- });
1320
- }
1321
-
1322
1260
  // ../node-auth/src/secure-token.ts
1323
1261
  var import_node_crypto2 = require("crypto");
1324
1262
 
@@ -1377,59 +1315,11 @@ function parsePositiveInteger(rawValue, fallback, minimum = 1) {
1377
1315
  const parsed = Number(normalized);
1378
1316
  return Number.isSafeInteger(parsed) && parsed >= minimum ? parsed : fallback;
1379
1317
  }
1380
- function normalizeApiBaseUrl(value) {
1381
- if (!value) return null;
1382
- const normalized = value.trim().replace(/\/+$/, "");
1383
- if (!normalized) return null;
1384
- let parsed;
1385
- try {
1386
- parsed = new URL(normalized);
1387
- } catch {
1388
- throw new Error(`Invalid ARCHAL_API_URL: "${normalized}" is not a valid URL`);
1389
- }
1390
- const isLocalhostHttp = parsed.protocol === "http:" && (parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1");
1391
- if (parsed.protocol !== "https:" && !isLocalhostHttp) {
1392
- throw new Error(`Hosted API URL must use HTTPS (or localhost HTTP). Received ${normalized}.`);
1393
- }
1394
- const pathname = parsed.pathname.replace(/\/+$/, "");
1395
- parsed.pathname = pathname.endsWith("/api") ? pathname.slice(0, -4) || "/" : pathname || "/";
1396
- parsed.search = "";
1397
- parsed.hash = "";
1398
- return parsed.toString().replace(/\/$/, "");
1399
- }
1400
1318
 
1401
1319
  // ../runtime/src/auth-lease.ts
1402
1320
  var STORED_CREDENTIALS_LOCK_TIMEOUT_MS = 3e4;
1403
1321
  var STORED_CREDENTIALS_STALE_LOCK_MS = STORED_CREDENTIALS_LOCK_TIMEOUT_MS;
1404
1322
  var STORED_CREDENTIALS_LOCK_POLL_INTERVAL_MS = 50;
1405
- var DEFAULT_AUTH_BASE_URL = "https://www.archal.ai";
1406
- var WORKSPACE_API_KEY_EXPIRES_SECONDS = 365 * 24 * 60 * 60;
1407
- function readFirstConfiguredBaseUrl(envVars) {
1408
- for (const envVar of envVars) {
1409
- const configured = trimEnv(envVar);
1410
- if (!configured) {
1411
- continue;
1412
- }
1413
- const normalized = normalizeApiBaseUrl(configured);
1414
- if (normalized) {
1415
- return normalized;
1416
- }
1417
- }
1418
- return null;
1419
- }
1420
- function resolveHostedAuthBaseUrl(options) {
1421
- const authUrlEnvVar = options.authUrlEnvVar ?? "ARCHAL_AUTH_URL";
1422
- const apiUrlEnvVar = options.apiUrlEnvVar ?? "ARCHAL_API_URL";
1423
- const envVars = [.../* @__PURE__ */ new Set([
1424
- apiUrlEnvVar,
1425
- authUrlEnvVar,
1426
- "ARCHAL_AUTH_URL",
1427
- "ARCHAL_AUTH_BASE_URL",
1428
- "ARCHAL_API_URL",
1429
- "ARCHAL_API_BASE_URL"
1430
- ])];
1431
- return readFirstConfiguredBaseUrl(envVars) ?? DEFAULT_AUTH_BASE_URL;
1432
- }
1433
1323
  function isImplicitTestSandboxFlow() {
1434
1324
  if (trimEnv("ARCHAL_HOME")) {
1435
1325
  return false;
@@ -1446,59 +1336,11 @@ function readExplicitEnvCredentials(envName) {
1446
1336
  if (!token) {
1447
1337
  return { kind: "missing" };
1448
1338
  }
1449
- const claims = decodeJwtPayload(token);
1450
- const nowSeconds = Math.floor(Date.now() / 1e3);
1451
- if (claims === null) {
1452
- if (isWorkspaceApiKey(token)) {
1453
- return {
1454
- kind: "valid",
1455
- credentials: {
1456
- token,
1457
- refreshToken: "",
1458
- email: "(workspace-api-key)",
1459
- plan: "pro",
1460
- selectedCloneIds: [],
1461
- expiresAt: nowSeconds + WORKSPACE_API_KEY_EXPIRES_SECONDS
1462
- }
1463
- };
1464
- }
1465
- return {
1466
- kind: "invalid",
1467
- message: `${envName} must be a JWT with valid plan and exp claims or a workspace API key (archal_ws_...).`
1468
- };
1469
- }
1470
- const email = typeof claims["email"] === "string" ? claims["email"] : `(from ${envName})`;
1471
- if (!isPlan(claims["plan"])) {
1472
- return {
1473
- kind: "invalid",
1474
- message: `${envName} JWT does not contain a valid plan claim.`
1475
- };
1339
+ const parsed = parseEnvToken(token, envName);
1340
+ if (parsed.status !== "ok") {
1341
+ return { kind: "invalid", message: parsed.message };
1476
1342
  }
1477
- const plan = claims["plan"];
1478
- if (typeof claims["exp"] !== "number" || !Number.isFinite(claims["exp"])) {
1479
- return {
1480
- kind: "invalid",
1481
- message: `${envName} JWT does not contain a valid exp claim.`
1482
- };
1483
- }
1484
- const expiresAt = claims["exp"];
1485
- if (expiresAt <= nowSeconds) {
1486
- return {
1487
- kind: "invalid",
1488
- message: `${envName} is expired. Remove it or replace it with a valid token.`
1489
- };
1490
- }
1491
- return {
1492
- kind: "valid",
1493
- credentials: {
1494
- token,
1495
- refreshToken: "",
1496
- email,
1497
- plan,
1498
- selectedCloneIds: [],
1499
- expiresAt
1500
- }
1501
- };
1343
+ return { kind: "valid", credentials: parsed.credentials };
1502
1344
  }
1503
1345
  function readStoredCredentials(includeExpired = false) {
1504
1346
  prepareStoredCredentialSources();
@@ -1615,7 +1457,15 @@ async function resolveCurrentCredentials(credentials, source, forceValidation, a
1615
1457
  }
1616
1458
  async function createHostedAuthLease(options = {}) {
1617
1459
  const tokenEnvVar = options.tokenEnvVar ?? "ARCHAL_TOKEN";
1618
- const authBaseUrl = resolveHostedAuthBaseUrl(options);
1460
+ const authBaseUrl = getConfiguredAuthValidationBaseUrl({
1461
+ apiUrlEnvVar: options.apiUrlEnvVar,
1462
+ authUrlEnvVar: options.authUrlEnvVar
1463
+ });
1464
+ if (!authBaseUrl) {
1465
+ throw new Error(
1466
+ "Hosted auth validation requires ARCHAL_AUTH_URL or ARCHAL_API_URL when ARCHAL_STRICT_ENDPOINTS=1."
1467
+ );
1468
+ }
1619
1469
  const resolved = resolveCredentialsWithSource(tokenEnvVar, true);
1620
1470
  if (!resolved) {
1621
1471
  const tokenSources = Array.from(/* @__PURE__ */ new Set([tokenEnvVar, "ARCHAL_TOKEN"])).join(", ");
@@ -4,7 +4,7 @@ import {
4
4
  createHostedAuthLease,
5
5
  parsePositiveInteger,
6
6
  runHostedSessionReaper
7
- } from "../chunk-ARVS45PP.js";
7
+ } from "../chunk-7L4BBB6M.js";
8
8
 
9
9
  // src/runtime/hosted-session-reaper.ts
10
10
  var VITEST_AUTH_LEASE_OPTIONS = {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  bootstrapArchalVitestRouting
3
- } from "../chunk-6CBYFCFK.js";
4
- import "../chunk-ARVS45PP.js";
3
+ } from "../chunk-2PDHTPZC.js";
4
+ import "../chunk-7L4BBB6M.js";
5
5
 
6
6
  // src/runtime/setup-files.ts
7
7
  import { existsSync, rmSync } from "fs";
package/manifest.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "version": 1,
3
+ "bundleKind": "archal-package-full",
4
+ "capabilities": [
5
+ "hosted-autoloop",
6
+ "clone-runtime",
7
+ "clone-free-autoloop"
8
+ ]
9
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "archal",
3
- "version": "0.9.20",
3
+ "version": "0.10.0",
4
4
  "description": "Test your agents & integrations against service clones",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -13,12 +13,10 @@
13
13
  "types": "./dist/index.d.cts",
14
14
  "default": "./dist/index.cjs"
15
15
  },
16
- "./harness": {
17
- "types": "./dist/harness.d.cts",
18
- "default": "./dist/harness.cjs"
19
- },
20
16
  "./scenarios": {
21
17
  "types": "./dist/scenarios.d.cts",
18
+ "import": "./dist/scenarios.cjs",
19
+ "require": "./dist/scenarios.cjs",
22
20
  "default": "./dist/scenarios.cjs"
23
21
  },
24
22
  "./vitest": {
@@ -49,13 +47,21 @@
49
47
  "files": [
50
48
  "bin",
51
49
  "dist",
50
+ "manifest.json",
52
51
  "skills",
53
52
  "clone-assets",
54
53
  "agents",
55
54
  "LICENSE"
56
55
  ],
56
+ "scripts": {
57
+ "verify:artifacts": "node scripts/assert-artifacts.mjs",
58
+ "prepack": "node scripts/assert-artifacts.mjs",
59
+ "prepare": "node scripts/prepare.cjs",
60
+ "typecheck:raw": "node --check bin/archal.cjs && node --check scripts/assert-artifacts.mjs && node --check scripts/prepare.cjs",
61
+ "typecheck": "pnpm run typecheck:raw"
62
+ },
57
63
  "peerDependencies": {
58
- "vitest": ">=2.1.0"
64
+ "vitest": ">=2.1.0 <3"
59
65
  },
60
66
  "peerDependenciesMeta": {
61
67
  "vitest": {
@@ -65,11 +71,6 @@
65
71
  "dependencies": {
66
72
  "@aws-sdk/client-secrets-manager": "^3.1065.0",
67
73
  "e2b": "^2.28.2",
68
- "picomatch": "^4.0.4"
69
- },
70
- "scripts": {
71
- "verify:artifacts": "node scripts/assert-artifacts.mjs",
72
- "typecheck:raw": "node --check bin/archal.cjs && node --check scripts/assert-artifacts.mjs && node --check scripts/prepare.cjs",
73
- "typecheck": "pnpm run typecheck:raw"
74
+ "tsx": "^4.19.0"
74
75
  }
75
- }
76
+ }
@@ -76,7 +76,6 @@ deeper flow.
76
76
 
77
77
  The Archal copilot is not locked to one model. When autofix reproduces a failure
78
78
  and writes a fix, the user can drive that remediation with their own agent —
79
- `archal preprod` exposes `--remediation-agent auto|codex|claude|cursor` so the
80
79
  fix is written by their Claude Code, Cursor, or Codex — or let Archal's managed
81
80
  agent do it. Mention this when the user asks who writes the fix or wants to use
82
81
  their own coding agent, then route to `autoloop`.