@morphllm/morphsdk 0.2.92 → 0.2.94

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 (86) hide show
  1. package/dist/{chunk-IJ54DTJ3.js → chunk-4WO7PJNT.js} +11 -11
  2. package/dist/{chunk-EYGBUH2R.js → chunk-AV6YV2MH.js} +2 -2
  3. package/dist/{chunk-LMUZ3NGC.js → chunk-BVVDDTI7.js} +2 -2
  4. package/dist/chunk-ESRZJRTQ.js +359 -0
  5. package/dist/chunk-ESRZJRTQ.js.map +1 -0
  6. package/dist/{chunk-GU6DACME.js → chunk-FIA6LBW2.js} +2 -2
  7. package/dist/{chunk-4WLGDYWQ.js → chunk-FMWNVTJJ.js} +2 -2
  8. package/dist/{chunk-PBLPZ6AU.js → chunk-IH3KN4AT.js} +2 -2
  9. package/dist/{chunk-MIIJWDOQ.js → chunk-M7GFXRKL.js} +13 -3
  10. package/dist/chunk-M7GFXRKL.js.map +1 -0
  11. package/dist/{chunk-4KMBU6T3.js → chunk-R7WN43L2.js} +4 -4
  12. package/dist/{chunk-PUGIOVSP.js → chunk-TXYCM4NP.js} +2 -2
  13. package/dist/chunk-UJ7LVT5G.js +177 -0
  14. package/dist/chunk-UJ7LVT5G.js.map +1 -0
  15. package/dist/{chunk-FNLNDMIX.js → chunk-WSQMWVSD.js} +2 -2
  16. package/dist/chunk-YJ354BA2.js +46 -0
  17. package/dist/chunk-YJ354BA2.js.map +1 -0
  18. package/dist/client.cjs +546 -4
  19. package/dist/client.cjs.map +1 -1
  20. package/dist/client.d.ts +2 -0
  21. package/dist/client.js +12 -9
  22. package/dist/index.cjs +546 -4
  23. package/dist/index.cjs.map +1 -1
  24. package/dist/index.d.ts +2 -0
  25. package/dist/index.js +12 -9
  26. package/dist/tools/browser/anthropic.cjs +5 -1
  27. package/dist/tools/browser/anthropic.cjs.map +1 -1
  28. package/dist/tools/browser/anthropic.js +5 -2
  29. package/dist/tools/browser/core.cjs +544 -2
  30. package/dist/tools/browser/core.cjs.map +1 -1
  31. package/dist/tools/browser/core.d.ts +6 -0
  32. package/dist/tools/browser/core.js +4 -1
  33. package/dist/tools/browser/errors.cjs +208 -0
  34. package/dist/tools/browser/errors.cjs.map +1 -0
  35. package/dist/tools/browser/errors.d.ts +158 -0
  36. package/dist/tools/browser/errors.js +22 -0
  37. package/dist/tools/browser/errors.js.map +1 -0
  38. package/dist/tools/browser/index.cjs +562 -2
  39. package/dist/tools/browser/index.cjs.map +1 -1
  40. package/dist/tools/browser/index.d.ts +3 -0
  41. package/dist/tools/browser/index.js +27 -4
  42. package/dist/tools/browser/index.js.map +1 -1
  43. package/dist/tools/browser/openai.cjs +5 -1
  44. package/dist/tools/browser/openai.cjs.map +1 -1
  45. package/dist/tools/browser/openai.js +5 -2
  46. package/dist/tools/browser/profiles/core.cjs +639 -0
  47. package/dist/tools/browser/profiles/core.cjs.map +1 -0
  48. package/dist/tools/browser/profiles/core.d.ts +179 -0
  49. package/dist/tools/browser/profiles/core.js +27 -0
  50. package/dist/tools/browser/profiles/core.js.map +1 -0
  51. package/dist/tools/browser/profiles/index.cjs +639 -0
  52. package/dist/tools/browser/profiles/index.cjs.map +1 -0
  53. package/dist/tools/browser/profiles/index.d.ts +4 -0
  54. package/dist/tools/browser/profiles/index.js +27 -0
  55. package/dist/tools/browser/profiles/index.js.map +1 -0
  56. package/dist/tools/browser/profiles/types.cjs +74 -0
  57. package/dist/tools/browser/profiles/types.cjs.map +1 -0
  58. package/dist/tools/browser/profiles/types.d.ts +176 -0
  59. package/dist/tools/browser/profiles/types.js +16 -0
  60. package/dist/tools/browser/profiles/types.js.map +1 -0
  61. package/dist/tools/browser/types.cjs.map +1 -1
  62. package/dist/tools/browser/types.d.ts +2 -0
  63. package/dist/tools/browser/vercel.cjs +5 -1
  64. package/dist/tools/browser/vercel.cjs.map +1 -1
  65. package/dist/tools/browser/vercel.js +5 -2
  66. package/dist/tools/fastapply/index.js +3 -3
  67. package/dist/tools/index.js +3 -3
  68. package/dist/tools/warp_grep/anthropic.js +4 -4
  69. package/dist/tools/warp_grep/client.js +3 -3
  70. package/dist/tools/warp_grep/gemini.js +3 -3
  71. package/dist/tools/warp_grep/harness.js +2 -2
  72. package/dist/tools/warp_grep/index.js +3 -3
  73. package/dist/tools/warp_grep/openai.js +4 -4
  74. package/dist/tools/warp_grep/providers/local.js +2 -2
  75. package/dist/tools/warp_grep/vercel.js +4 -4
  76. package/package.json +7 -2
  77. package/dist/chunk-MIIJWDOQ.js.map +0 -1
  78. /package/dist/{chunk-IJ54DTJ3.js.map → chunk-4WO7PJNT.js.map} +0 -0
  79. /package/dist/{chunk-EYGBUH2R.js.map → chunk-AV6YV2MH.js.map} +0 -0
  80. /package/dist/{chunk-LMUZ3NGC.js.map → chunk-BVVDDTI7.js.map} +0 -0
  81. /package/dist/{chunk-GU6DACME.js.map → chunk-FIA6LBW2.js.map} +0 -0
  82. /package/dist/{chunk-4WLGDYWQ.js.map → chunk-FMWNVTJJ.js.map} +0 -0
  83. /package/dist/{chunk-PBLPZ6AU.js.map → chunk-IH3KN4AT.js.map} +0 -0
  84. /package/dist/{chunk-4KMBU6T3.js.map → chunk-R7WN43L2.js.map} +0 -0
  85. /package/dist/{chunk-PUGIOVSP.js.map → chunk-TXYCM4NP.js.map} +0 -0
  86. /package/dist/{chunk-FNLNDMIX.js.map → chunk-WSQMWVSD.js.map} +0 -0
package/dist/client.d.ts CHANGED
@@ -9,6 +9,8 @@ export { M as MorphClient, a as MorphClientConfig } from './client-BVeUudyD.js';
9
9
  import './tools/fastapply/types.js';
10
10
  import './tools/codebase_search/types.js';
11
11
  import './tools/browser/types.js';
12
+ import './tools/browser/profiles/core.js';
13
+ import './tools/browser/profiles/types.js';
12
14
  import './tools/warp_grep/agent/types.js';
13
15
  import './types-BMowL9iZ.js';
14
16
  import './tools/warp_grep/providers/types.js';
package/dist/client.js CHANGED
@@ -1,33 +1,36 @@
1
1
  import {
2
2
  MorphClient
3
- } from "./chunk-IJ54DTJ3.js";
4
- import "./chunk-PBLPZ6AU.js";
5
- import "./chunk-LMUZ3NGC.js";
6
- import "./chunk-GU6DACME.js";
3
+ } from "./chunk-4WO7PJNT.js";
4
+ import "./chunk-FIA6LBW2.js";
5
+ import "./chunk-IH3KN4AT.js";
6
+ import "./chunk-BVVDDTI7.js";
7
7
  import "./chunk-KW7OEGZK.js";
8
- import "./chunk-PUGIOVSP.js";
8
+ import "./chunk-TXYCM4NP.js";
9
9
  import "./chunk-VHOWYK66.js";
10
10
  import "./chunk-PUGSTXLO.js";
11
11
  import "./chunk-KRDIR7GG.js";
12
12
  import "./chunk-APP75CBN.js";
13
13
  import "./chunk-SNGGSPYJ.js";
14
14
  import "./chunk-FMLHRJDF.js";
15
- import "./chunk-4KMBU6T3.js";
16
- import "./chunk-G2RSY56Q.js";
15
+ import "./chunk-R7WN43L2.js";
17
16
  import "./chunk-YPKNMYD4.js";
18
17
  import "./chunk-TPP2UGQP.js";
19
18
  import "./chunk-5PNMAWLC.js";
19
+ import "./chunk-G2RSY56Q.js";
20
20
  import "./chunk-UBX7QYBD.js";
21
21
  import "./chunk-GJU7UOFL.js";
22
22
  import "./chunk-76DJEQEP.js";
23
23
  import "./chunk-WM77HRKO.js";
24
24
  import "./chunk-YQMPVJ2L.js";
25
+ import "./chunk-QZNGKOCZ.js";
25
26
  import "./chunk-IUG2FHNN.js";
26
27
  import "./chunk-5QIWYEHJ.js";
27
- import "./chunk-QZNGKOCZ.js";
28
28
  import "./chunk-CKTA4AXM.js";
29
29
  import "./chunk-63WE2C5R.js";
30
- import "./chunk-MIIJWDOQ.js";
30
+ import "./chunk-M7GFXRKL.js";
31
+ import "./chunk-ESRZJRTQ.js";
32
+ import "./chunk-YJ354BA2.js";
33
+ import "./chunk-UJ7LVT5G.js";
31
34
  import "./chunk-SQN4DUQS.js";
32
35
  import "./chunk-GZMUGMOZ.js";
33
36
  import "./chunk-VJU3BRET.js";
package/dist/index.cjs CHANGED
@@ -515,6 +515,541 @@ function resolvePreset(optionsOrPreset) {
515
515
  return optionsOrPreset;
516
516
  }
517
517
 
518
+ // tools/browser/errors.ts
519
+ var MorphError = class extends Error {
520
+ /** Error code for programmatic handling */
521
+ code;
522
+ /** Original cause of the error, if any */
523
+ cause;
524
+ constructor(message, code, cause) {
525
+ super(message);
526
+ this.name = "MorphError";
527
+ this.code = code;
528
+ this.cause = cause;
529
+ if (Error.captureStackTrace) {
530
+ Error.captureStackTrace(this, this.constructor);
531
+ }
532
+ }
533
+ /**
534
+ * Returns a JSON representation of the error for logging.
535
+ */
536
+ toJSON() {
537
+ return {
538
+ name: this.name,
539
+ message: this.message,
540
+ code: this.code,
541
+ cause: this.cause?.message
542
+ };
543
+ }
544
+ };
545
+ var MorphValidationError = class extends MorphError {
546
+ /** The field that failed validation */
547
+ field;
548
+ constructor(message, field) {
549
+ super(message, "validation_error");
550
+ this.name = "MorphValidationError";
551
+ this.field = field;
552
+ }
553
+ toJSON() {
554
+ return {
555
+ ...super.toJSON(),
556
+ field: this.field
557
+ };
558
+ }
559
+ };
560
+ var MorphAPIError = class extends MorphError {
561
+ /** HTTP status code */
562
+ statusCode;
563
+ /** Request ID for debugging (if available) */
564
+ requestId;
565
+ /** Raw response body */
566
+ rawResponse;
567
+ constructor(message, code, statusCode, options) {
568
+ super(message, code, options?.cause);
569
+ this.name = "MorphAPIError";
570
+ this.statusCode = statusCode;
571
+ this.requestId = options?.requestId;
572
+ this.rawResponse = options?.rawResponse;
573
+ }
574
+ toJSON() {
575
+ return {
576
+ ...super.toJSON(),
577
+ statusCode: this.statusCode,
578
+ requestId: this.requestId
579
+ };
580
+ }
581
+ };
582
+ var MorphAuthenticationError = class extends MorphAPIError {
583
+ constructor(message = "Authentication required. Please provide a valid API key.") {
584
+ super(message, "authentication_required", 401);
585
+ this.name = "MorphAuthenticationError";
586
+ }
587
+ };
588
+ var MorphRateLimitError = class extends MorphAPIError {
589
+ /** When the rate limit resets (Unix timestamp) */
590
+ resetAt;
591
+ /** Number of seconds until reset */
592
+ retryAfter;
593
+ constructor(message = "Rate limit exceeded. Please retry later.", options) {
594
+ super(message, "rate_limit_exceeded", 429, { requestId: options?.requestId });
595
+ this.name = "MorphRateLimitError";
596
+ this.resetAt = options?.resetAt;
597
+ this.retryAfter = options?.retryAfter;
598
+ }
599
+ toJSON() {
600
+ return {
601
+ ...super.toJSON(),
602
+ resetAt: this.resetAt,
603
+ retryAfter: this.retryAfter
604
+ };
605
+ }
606
+ };
607
+ var MorphNotFoundError = class extends MorphAPIError {
608
+ /** The type of resource that was not found */
609
+ resourceType;
610
+ /** The ID of the resource that was not found */
611
+ resourceId;
612
+ constructor(resourceType, resourceId) {
613
+ const message = resourceId ? `${resourceType} '${resourceId}' not found` : `${resourceType} not found`;
614
+ super(message, "resource_not_found", 404);
615
+ this.name = "MorphNotFoundError";
616
+ this.resourceType = resourceType;
617
+ this.resourceId = resourceId;
618
+ }
619
+ toJSON() {
620
+ return {
621
+ ...super.toJSON(),
622
+ resourceType: this.resourceType,
623
+ resourceId: this.resourceId
624
+ };
625
+ }
626
+ };
627
+ var MorphProfileLimitError = class extends MorphAPIError {
628
+ /** Current number of profiles */
629
+ currentCount;
630
+ /** Maximum allowed profiles for the plan */
631
+ maxAllowed;
632
+ constructor(message = "Profile limit exceeded for your plan.", options) {
633
+ super(message, "profile_limit_exceeded", 403, { requestId: options?.requestId });
634
+ this.name = "MorphProfileLimitError";
635
+ this.currentCount = options?.currentCount;
636
+ this.maxAllowed = options?.maxAllowed;
637
+ }
638
+ toJSON() {
639
+ return {
640
+ ...super.toJSON(),
641
+ currentCount: this.currentCount,
642
+ maxAllowed: this.maxAllowed
643
+ };
644
+ }
645
+ };
646
+ function parseAPIError(statusCode, responseText, requestId) {
647
+ let errorData = {};
648
+ try {
649
+ errorData = JSON.parse(responseText);
650
+ } catch {
651
+ }
652
+ const message = errorData.detail || errorData.message || responseText || "Unknown error";
653
+ const code = errorData.code;
654
+ switch (statusCode) {
655
+ case 401:
656
+ return new MorphAuthenticationError(message);
657
+ case 403:
658
+ if (code === "profile_limit_exceeded" || message.toLowerCase().includes("limit")) {
659
+ return new MorphProfileLimitError(message, { requestId });
660
+ }
661
+ return new MorphAPIError(message, "insufficient_permissions", statusCode, { requestId, rawResponse: responseText });
662
+ case 404:
663
+ if (message.toLowerCase().includes("profile")) {
664
+ return new MorphNotFoundError("Profile", void 0);
665
+ }
666
+ if (message.toLowerCase().includes("session")) {
667
+ return new MorphNotFoundError("Session", void 0);
668
+ }
669
+ return new MorphAPIError(message, "resource_not_found", statusCode, { requestId, rawResponse: responseText });
670
+ case 429:
671
+ return new MorphRateLimitError(message, { requestId });
672
+ case 422:
673
+ return new MorphAPIError(message, "validation_error", statusCode, { requestId, rawResponse: responseText });
674
+ case 500:
675
+ case 502:
676
+ case 503:
677
+ case 504:
678
+ return new MorphAPIError(message, "service_unavailable", statusCode, { requestId, rawResponse: responseText });
679
+ default:
680
+ return new MorphAPIError(message, "network_error", statusCode, { requestId, rawResponse: responseText });
681
+ }
682
+ }
683
+
684
+ // tools/browser/profiles/types.ts
685
+ function transformProfile(api) {
686
+ return {
687
+ id: api.id,
688
+ name: api.name,
689
+ repoId: api.repo_id,
690
+ cookieDomains: api.cookie_domains,
691
+ lastUsedAt: api.last_used_at,
692
+ createdAt: api.created_at,
693
+ updatedAt: api.updated_at
694
+ };
695
+ }
696
+ function transformCreateInput(input) {
697
+ return {
698
+ name: input.name,
699
+ repo_id: input.repoId
700
+ };
701
+ }
702
+ function transformSession(api) {
703
+ return {
704
+ sessionId: api.session_id,
705
+ debugUrl: api.debug_url || api.debugUrl || ""
706
+ };
707
+ }
708
+ function transformSaveInput(input) {
709
+ return {
710
+ session_id: input.sessionId,
711
+ profile_id: input.profileId
712
+ };
713
+ }
714
+ function transformStateResponse(api) {
715
+ return {
716
+ profileId: api.profile_id,
717
+ stateUrl: api.state_url,
718
+ expiresIn: api.expires_in
719
+ };
720
+ }
721
+
722
+ // tools/browser/profiles/core.ts
723
+ var DEFAULT_API_URL = process.env.MORPH_ENVIRONMENT === "DEV" ? "http://localhost:8000" : "https://browser.morphllm.com";
724
+ var ProfilesClient = class {
725
+ config;
726
+ constructor(config) {
727
+ this.config = config;
728
+ }
729
+ /**
730
+ * Create a new browser profile.
731
+ *
732
+ * @param input - Profile creation parameters
733
+ * @returns The created profile
734
+ * @throws {MorphValidationError} If input validation fails
735
+ * @throws {MorphProfileLimitError} If profile limit is exceeded
736
+ * @throws {MorphAuthenticationError} If API key is missing or invalid
737
+ *
738
+ * @example
739
+ * ```typescript
740
+ * const profile = await morph.browser.profiles.createProfile({
741
+ * name: 'LinkedIn Production',
742
+ * repoId: 'repo-uuid-here'
743
+ * });
744
+ * ```
745
+ */
746
+ async createProfile(input) {
747
+ return createProfile(input, this.config);
748
+ }
749
+ /**
750
+ * List all profiles for the authenticated user.
751
+ *
752
+ * @param repoId - Optional repository ID to filter by
753
+ * @returns Array of profiles
754
+ *
755
+ * @example
756
+ * ```typescript
757
+ * // List all profiles
758
+ * const allProfiles = await morph.browser.profiles.listProfiles();
759
+ *
760
+ * // List profiles for a specific repo
761
+ * const repoProfiles = await morph.browser.profiles.listProfiles('repo-uuid');
762
+ * ```
763
+ */
764
+ async listProfiles(repoId) {
765
+ return listProfiles(this.config, repoId);
766
+ }
767
+ /**
768
+ * Get a profile by ID with convenience methods.
769
+ *
770
+ * @param id - Profile ID
771
+ * @returns Profile with attached methods
772
+ * @throws {MorphNotFoundError} If profile is not found
773
+ *
774
+ * @example
775
+ * ```typescript
776
+ * const profile = await morph.browser.profiles.getProfile('profile-id');
777
+ * const state = await profile.getState();
778
+ * await profile.delete();
779
+ * ```
780
+ */
781
+ async getProfile(id) {
782
+ return getProfile(id, this.config);
783
+ }
784
+ /**
785
+ * Update a profile's name.
786
+ *
787
+ * @param id - Profile ID
788
+ * @param input - Update parameters
789
+ * @returns Updated profile
790
+ */
791
+ async updateProfile(id, input) {
792
+ return updateProfile(id, input, this.config);
793
+ }
794
+ /**
795
+ * Delete a profile.
796
+ *
797
+ * @param id - Profile ID
798
+ * @throws {MorphNotFoundError} If profile is not found
799
+ */
800
+ async deleteProfile(id) {
801
+ return deleteProfile(id, this.config);
802
+ }
803
+ /**
804
+ * Start a browser session for profile setup.
805
+ *
806
+ * Returns a live URL where the user can sign into accounts.
807
+ * After signing in, call `saveSession` to persist the state.
808
+ *
809
+ * @param input - Optional session parameters
810
+ * @returns Session with debug URL
811
+ *
812
+ * @example
813
+ * ```typescript
814
+ * const session = await morph.browser.profiles.startSession();
815
+ * console.log('Sign in at:', session.debugUrl);
816
+ * // Open debugUrl in browser, user signs in...
817
+ * await morph.browser.profiles.saveSession(session.sessionId, profile.id);
818
+ * ```
819
+ */
820
+ async startSession(input) {
821
+ return startProfileSession(this.config, input);
822
+ }
823
+ /**
824
+ * Save browser state from a session to a profile.
825
+ *
826
+ * Call this after the user is done signing into accounts.
827
+ * Extracts cookies, localStorage, and sessionStorage.
828
+ *
829
+ * @param sessionId - Browser session ID from startSession
830
+ * @param profileId - Profile ID to save state to
831
+ * @returns Updated profile with cookie domains
832
+ */
833
+ async saveSession(sessionId, profileId) {
834
+ return saveProfileSession({ sessionId, profileId }, this.config);
835
+ }
836
+ /**
837
+ * Get the presigned URL for a profile's state.
838
+ *
839
+ * Use this to download the raw state JSON for debugging
840
+ * or to restore state manually.
841
+ *
842
+ * @param profileId - Profile ID
843
+ * @returns State URL with expiry information
844
+ */
845
+ async getProfileState(profileId) {
846
+ return getProfileState(profileId, this.config);
847
+ }
848
+ };
849
+ function validateCreateInput(input) {
850
+ if (!input.name || typeof input.name !== "string") {
851
+ throw new MorphValidationError("name is required", "name");
852
+ }
853
+ const trimmedName = input.name.trim();
854
+ if (trimmedName.length === 0) {
855
+ throw new MorphValidationError("name cannot be empty", "name");
856
+ }
857
+ if (trimmedName.length > 100) {
858
+ throw new MorphValidationError("name must be 100 characters or less", "name");
859
+ }
860
+ if (!input.repoId || typeof input.repoId !== "string") {
861
+ throw new MorphValidationError("repoId is required", "repoId");
862
+ }
863
+ if (input.repoId.trim().length === 0) {
864
+ throw new MorphValidationError("repoId cannot be empty", "repoId");
865
+ }
866
+ }
867
+ function validateId(id, fieldName) {
868
+ if (!id || typeof id !== "string") {
869
+ throw new MorphValidationError(`${fieldName} is required`, fieldName);
870
+ }
871
+ if (id.trim().length === 0) {
872
+ throw new MorphValidationError(`${fieldName} cannot be empty`, fieldName);
873
+ }
874
+ }
875
+ async function createProfile(input, config = {}) {
876
+ validateCreateInput(input);
877
+ const apiUrl = config.apiUrl || DEFAULT_API_URL;
878
+ const headers = buildHeaders(config);
879
+ const response = await fetchWithRetry(
880
+ `${apiUrl}/profiles`,
881
+ {
882
+ method: "POST",
883
+ headers,
884
+ body: JSON.stringify(transformCreateInput(input))
885
+ },
886
+ config.retryConfig
887
+ );
888
+ if (!response.ok) {
889
+ const errorText = await response.text().catch(() => response.statusText);
890
+ const requestId = response.headers.get("x-request-id") || void 0;
891
+ throw parseAPIError(response.status, errorText, requestId);
892
+ }
893
+ const apiProfile = await response.json();
894
+ return transformProfile(apiProfile);
895
+ }
896
+ async function listProfiles(config = {}, repoId) {
897
+ const apiUrl = config.apiUrl || DEFAULT_API_URL;
898
+ const headers = buildHeaders(config);
899
+ const url = repoId ? `${apiUrl}/profiles?repo_id=${encodeURIComponent(repoId)}` : `${apiUrl}/profiles`;
900
+ const response = await fetchWithRetry(
901
+ url,
902
+ { method: "GET", headers },
903
+ config.retryConfig
904
+ );
905
+ if (!response.ok) {
906
+ const errorText = await response.text().catch(() => response.statusText);
907
+ const requestId = response.headers.get("x-request-id") || void 0;
908
+ throw parseAPIError(response.status, errorText, requestId);
909
+ }
910
+ const data = await response.json();
911
+ return data.profiles.map(transformProfile);
912
+ }
913
+ async function getProfile(id, config = {}) {
914
+ validateId(id, "id");
915
+ const apiUrl = config.apiUrl || DEFAULT_API_URL;
916
+ const headers = buildHeaders(config);
917
+ const response = await fetchWithRetry(
918
+ `${apiUrl}/profiles/${encodeURIComponent(id)}`,
919
+ { method: "GET", headers },
920
+ config.retryConfig
921
+ );
922
+ if (!response.ok) {
923
+ const errorText = await response.text().catch(() => response.statusText);
924
+ const requestId = response.headers.get("x-request-id") || void 0;
925
+ throw parseAPIError(response.status, errorText, requestId);
926
+ }
927
+ const apiProfile = await response.json();
928
+ const profile = transformProfile(apiProfile);
929
+ return {
930
+ ...profile,
931
+ getState: () => getProfileState(id, config),
932
+ delete: () => deleteProfile(id, config)
933
+ };
934
+ }
935
+ async function updateProfile(id, input, config = {}) {
936
+ validateId(id, "id");
937
+ if (input.name !== void 0) {
938
+ if (typeof input.name !== "string") {
939
+ throw new MorphValidationError("name must be a string", "name");
940
+ }
941
+ if (input.name.trim().length === 0) {
942
+ throw new MorphValidationError("name cannot be empty", "name");
943
+ }
944
+ if (input.name.length > 100) {
945
+ throw new MorphValidationError("name must be 100 characters or less", "name");
946
+ }
947
+ }
948
+ const apiUrl = config.apiUrl || DEFAULT_API_URL;
949
+ const headers = buildHeaders(config);
950
+ const response = await fetchWithRetry(
951
+ `${apiUrl}/profiles/${encodeURIComponent(id)}`,
952
+ {
953
+ method: "PATCH",
954
+ headers,
955
+ body: JSON.stringify(input)
956
+ },
957
+ config.retryConfig
958
+ );
959
+ if (!response.ok) {
960
+ const errorText = await response.text().catch(() => response.statusText);
961
+ const requestId = response.headers.get("x-request-id") || void 0;
962
+ throw parseAPIError(response.status, errorText, requestId);
963
+ }
964
+ const apiProfile = await response.json();
965
+ return transformProfile(apiProfile);
966
+ }
967
+ async function deleteProfile(id, config = {}) {
968
+ validateId(id, "id");
969
+ const apiUrl = config.apiUrl || DEFAULT_API_URL;
970
+ const headers = buildHeaders(config);
971
+ const response = await fetchWithRetry(
972
+ `${apiUrl}/profiles/${encodeURIComponent(id)}`,
973
+ { method: "DELETE", headers },
974
+ config.retryConfig
975
+ );
976
+ if (!response.ok) {
977
+ const errorText = await response.text().catch(() => response.statusText);
978
+ const requestId = response.headers.get("x-request-id") || void 0;
979
+ throw parseAPIError(response.status, errorText, requestId);
980
+ }
981
+ }
982
+ async function startProfileSession(config = {}, input) {
983
+ if (!config.apiKey) {
984
+ throw new MorphAuthenticationError();
985
+ }
986
+ const apiUrl = config.apiUrl || DEFAULT_API_URL;
987
+ const headers = buildHeaders(config);
988
+ const body = input?.profileId ? { profile_id: input.profileId } : {};
989
+ const response = await fetchWithRetry(
990
+ `${apiUrl}/profiles/session/start`,
991
+ {
992
+ method: "POST",
993
+ headers,
994
+ body: JSON.stringify(body)
995
+ },
996
+ config.retryConfig
997
+ );
998
+ if (!response.ok) {
999
+ const errorText = await response.text().catch(() => response.statusText);
1000
+ const requestId = response.headers.get("x-request-id") || void 0;
1001
+ throw parseAPIError(response.status, errorText, requestId);
1002
+ }
1003
+ const apiSession = await response.json();
1004
+ return transformSession(apiSession);
1005
+ }
1006
+ async function saveProfileSession(input, config = {}) {
1007
+ validateId(input.sessionId, "sessionId");
1008
+ validateId(input.profileId, "profileId");
1009
+ const apiUrl = config.apiUrl || DEFAULT_API_URL;
1010
+ const headers = buildHeaders(config);
1011
+ const response = await fetchWithRetry(
1012
+ `${apiUrl}/profiles/session/save`,
1013
+ {
1014
+ method: "POST",
1015
+ headers,
1016
+ body: JSON.stringify(transformSaveInput(input))
1017
+ },
1018
+ config.retryConfig
1019
+ );
1020
+ if (!response.ok) {
1021
+ const errorText = await response.text().catch(() => response.statusText);
1022
+ const requestId = response.headers.get("x-request-id") || void 0;
1023
+ throw parseAPIError(response.status, errorText, requestId);
1024
+ }
1025
+ const apiProfile = await response.json();
1026
+ return transformProfile(apiProfile);
1027
+ }
1028
+ async function getProfileState(profileId, config = {}) {
1029
+ validateId(profileId, "profileId");
1030
+ const apiUrl = config.apiUrl || DEFAULT_API_URL;
1031
+ const headers = buildHeaders(config);
1032
+ const response = await fetchWithRetry(
1033
+ `${apiUrl}/profiles/${encodeURIComponent(profileId)}/state`,
1034
+ { method: "GET", headers },
1035
+ config.retryConfig
1036
+ );
1037
+ if (!response.ok) {
1038
+ const errorText = await response.text().catch(() => response.statusText);
1039
+ const requestId = response.headers.get("x-request-id") || void 0;
1040
+ throw parseAPIError(response.status, errorText, requestId);
1041
+ }
1042
+ const apiState = await response.json();
1043
+ return transformStateResponse(apiState);
1044
+ }
1045
+ function buildHeaders(config) {
1046
+ const headers = { "Content-Type": "application/json" };
1047
+ if (config.apiKey) {
1048
+ headers["Authorization"] = `Bearer ${config.apiKey}`;
1049
+ }
1050
+ return headers;
1051
+ }
1052
+
518
1053
  // tools/browser/core.ts
519
1054
  var DEFAULT_CONFIG2 = {
520
1055
  apiUrl: process.env.MORPH_ENVIRONMENT === "DEV" ? "http://localhost:8000" : "https://browser.morphllm.com",
@@ -524,11 +1059,16 @@ var DEFAULT_CONFIG2 = {
524
1059
  };
525
1060
  var BrowserClient = class {
526
1061
  config;
1062
+ /**
1063
+ * Profile management - create and manage browser profiles for storing login state.
1064
+ */
1065
+ profiles;
527
1066
  constructor(config = {}) {
528
1067
  this.config = {
529
1068
  ...DEFAULT_CONFIG2,
530
1069
  ...config
531
1070
  };
1071
+ this.profiles = new ProfilesClient(this.config);
532
1072
  }
533
1073
  /**
534
1074
  * Execute a browser automation task
@@ -563,7 +1103,8 @@ var BrowserClient = class {
563
1103
  video_height: input.video_height ?? input.viewport_height ?? 720,
564
1104
  allow_resizing: input.allow_resizing ?? false,
565
1105
  structured_output: "schema" in input ? stringifyStructuredOutput(input.schema) : void 0,
566
- auth: input.auth
1106
+ auth: input.auth,
1107
+ profile_id: input.profile_id
567
1108
  })
568
1109
  });
569
1110
  if (!response.ok) {
@@ -662,7 +1203,8 @@ async function executeBrowserTask(input, config = {}) {
662
1203
  video_height: input.video_height ?? input.viewport_height ?? 720,
663
1204
  allow_resizing: input.allow_resizing ?? false,
664
1205
  structured_output: input.structured_output,
665
- auth: input.auth
1206
+ auth: input.auth,
1207
+ profile_id: input.profile_id
666
1208
  })
667
1209
  },
668
1210
  config.retryConfig
@@ -1867,9 +2409,9 @@ function enforceContextLimit(messages, maxChars = AGENT_CONFIG.MAX_CONTEXT_CHARS
1867
2409
  // tools/warp_grep/agent/runner.ts
1868
2410
  var import_path3 = __toESM(require("path"), 1);
1869
2411
  var parser = new LLMResponseParser();
1870
- var DEFAULT_API_URL = "https://api.morphllm.com";
2412
+ var DEFAULT_API_URL2 = "https://api.morphllm.com";
1871
2413
  async function callModel(messages, model, options = {}) {
1872
- const baseUrl = options.morphApiUrl || DEFAULT_API_URL;
2414
+ const baseUrl = options.morphApiUrl || DEFAULT_API_URL2;
1873
2415
  const apiKey = options.morphApiKey || process.env.MORPH_API_KEY || "";
1874
2416
  const fetchPromise = fetchWithRetry(
1875
2417
  `${baseUrl}/v1/chat/completions`,