@morphllm/morphsdk 0.2.6

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 (168) hide show
  1. package/README.md +39 -0
  2. package/dist/chunk-4UVEBIDK.js +358 -0
  3. package/dist/chunk-4UVEBIDK.js.map +1 -0
  4. package/dist/chunk-4V46N27D.js +169 -0
  5. package/dist/chunk-4V46N27D.js.map +1 -0
  6. package/dist/chunk-4VWJFZVS.js +89 -0
  7. package/dist/chunk-4VWJFZVS.js.map +1 -0
  8. package/dist/chunk-5COKN3XD.js +91 -0
  9. package/dist/chunk-5COKN3XD.js.map +1 -0
  10. package/dist/chunk-5VQEQSJQ.js +394 -0
  11. package/dist/chunk-5VQEQSJQ.js.map +1 -0
  12. package/dist/chunk-63WE2C5R.js +43 -0
  13. package/dist/chunk-63WE2C5R.js.map +1 -0
  14. package/dist/chunk-74ZHKB54.js +9 -0
  15. package/dist/chunk-74ZHKB54.js.map +1 -0
  16. package/dist/chunk-7PZJQFCY.js +39 -0
  17. package/dist/chunk-7PZJQFCY.js.map +1 -0
  18. package/dist/chunk-BILUTNBC.js +83 -0
  19. package/dist/chunk-BILUTNBC.js.map +1 -0
  20. package/dist/chunk-G4DJ6VSM.js +78 -0
  21. package/dist/chunk-G4DJ6VSM.js.map +1 -0
  22. package/dist/chunk-HGIFACNP.js +59 -0
  23. package/dist/chunk-HGIFACNP.js.map +1 -0
  24. package/dist/chunk-OI5YYE36.js +189 -0
  25. package/dist/chunk-OI5YYE36.js.map +1 -0
  26. package/dist/chunk-PZ5AY32C.js +10 -0
  27. package/dist/chunk-PZ5AY32C.js.map +1 -0
  28. package/dist/chunk-VJK4PH5V.js +105 -0
  29. package/dist/chunk-VJK4PH5V.js.map +1 -0
  30. package/dist/chunk-WXBUVKYL.js +128 -0
  31. package/dist/chunk-WXBUVKYL.js.map +1 -0
  32. package/dist/chunk-X2K57BH6.js +1 -0
  33. package/dist/chunk-X2K57BH6.js.map +1 -0
  34. package/dist/chunk-YQMPVJ2L.js +32 -0
  35. package/dist/chunk-YQMPVJ2L.js.map +1 -0
  36. package/dist/chunk-YWS2GRQC.js +97 -0
  37. package/dist/chunk-YWS2GRQC.js.map +1 -0
  38. package/dist/chunk-ZQEWQ7LJ.js +97 -0
  39. package/dist/chunk-ZQEWQ7LJ.js.map +1 -0
  40. package/dist/client.cjs +1358 -0
  41. package/dist/client.cjs.map +1 -0
  42. package/dist/client.js +15 -0
  43. package/dist/client.js.map +1 -0
  44. package/dist/git/client.cjs +428 -0
  45. package/dist/git/client.cjs.map +1 -0
  46. package/dist/git/client.js +8 -0
  47. package/dist/git/client.js.map +1 -0
  48. package/dist/git/config.cjs +41 -0
  49. package/dist/git/config.cjs.map +1 -0
  50. package/dist/git/config.js +17 -0
  51. package/dist/git/config.js.map +1 -0
  52. package/dist/git/index.cjs +438 -0
  53. package/dist/git/index.cjs.map +1 -0
  54. package/dist/git/index.js +14 -0
  55. package/dist/git/index.js.map +1 -0
  56. package/dist/git/types.cjs +19 -0
  57. package/dist/git/types.cjs.map +1 -0
  58. package/dist/git/types.js +1 -0
  59. package/dist/git/types.js.map +1 -0
  60. package/dist/index.cjs +1372 -0
  61. package/dist/index.cjs.map +1 -0
  62. package/dist/index.js +34 -0
  63. package/dist/index.js.map +1 -0
  64. package/dist/tools/browser/anthropic.cjs +281 -0
  65. package/dist/tools/browser/anthropic.cjs.map +1 -0
  66. package/dist/tools/browser/anthropic.js +72 -0
  67. package/dist/tools/browser/anthropic.js.map +1 -0
  68. package/dist/tools/browser/core.cjs +459 -0
  69. package/dist/tools/browser/core.cjs.map +1 -0
  70. package/dist/tools/browser/core.js +21 -0
  71. package/dist/tools/browser/core.js.map +1 -0
  72. package/dist/tools/browser/index.cjs +497 -0
  73. package/dist/tools/browser/index.cjs.map +1 -0
  74. package/dist/tools/browser/index.js +27 -0
  75. package/dist/tools/browser/index.js.map +1 -0
  76. package/dist/tools/browser/openai.cjs +297 -0
  77. package/dist/tools/browser/openai.cjs.map +1 -0
  78. package/dist/tools/browser/openai.js +85 -0
  79. package/dist/tools/browser/openai.js.map +1 -0
  80. package/dist/tools/browser/prompts.cjs +64 -0
  81. package/dist/tools/browser/prompts.cjs.map +1 -0
  82. package/dist/tools/browser/prompts.js +10 -0
  83. package/dist/tools/browser/prompts.js.map +1 -0
  84. package/dist/tools/browser/types.cjs +19 -0
  85. package/dist/tools/browser/types.cjs.map +1 -0
  86. package/dist/tools/browser/types.js +1 -0
  87. package/dist/tools/browser/types.js.map +1 -0
  88. package/dist/tools/browser/vercel.cjs +242 -0
  89. package/dist/tools/browser/vercel.cjs.map +1 -0
  90. package/dist/tools/browser/vercel.js +49 -0
  91. package/dist/tools/browser/vercel.js.map +1 -0
  92. package/dist/tools/codebase_search/anthropic.cjs +267 -0
  93. package/dist/tools/codebase_search/anthropic.cjs.map +1 -0
  94. package/dist/tools/codebase_search/anthropic.js +11 -0
  95. package/dist/tools/codebase_search/anthropic.js.map +1 -0
  96. package/dist/tools/codebase_search/core.cjs +201 -0
  97. package/dist/tools/codebase_search/core.cjs.map +1 -0
  98. package/dist/tools/codebase_search/core.js +11 -0
  99. package/dist/tools/codebase_search/core.js.map +1 -0
  100. package/dist/tools/codebase_search/index.cjs +393 -0
  101. package/dist/tools/codebase_search/index.cjs.map +1 -0
  102. package/dist/tools/codebase_search/index.js +27 -0
  103. package/dist/tools/codebase_search/index.js.map +1 -0
  104. package/dist/tools/codebase_search/openai.cjs +316 -0
  105. package/dist/tools/codebase_search/openai.cjs.map +1 -0
  106. package/dist/tools/codebase_search/openai.js +21 -0
  107. package/dist/tools/codebase_search/openai.js.map +1 -0
  108. package/dist/tools/codebase_search/prompts.cjs +57 -0
  109. package/dist/tools/codebase_search/prompts.cjs.map +1 -0
  110. package/dist/tools/codebase_search/prompts.js +10 -0
  111. package/dist/tools/codebase_search/prompts.js.map +1 -0
  112. package/dist/tools/codebase_search/types.cjs +19 -0
  113. package/dist/tools/codebase_search/types.cjs.map +1 -0
  114. package/dist/tools/codebase_search/types.js +1 -0
  115. package/dist/tools/codebase_search/types.js.map +1 -0
  116. package/dist/tools/codebase_search/vercel.cjs +230 -0
  117. package/dist/tools/codebase_search/vercel.cjs.map +1 -0
  118. package/dist/tools/codebase_search/vercel.js +15 -0
  119. package/dist/tools/codebase_search/vercel.js.map +1 -0
  120. package/dist/tools/fastapply/anthropic.cjs +335 -0
  121. package/dist/tools/fastapply/anthropic.cjs.map +1 -0
  122. package/dist/tools/fastapply/anthropic.js +13 -0
  123. package/dist/tools/fastapply/anthropic.js.map +1 -0
  124. package/dist/tools/fastapply/core.cjs +267 -0
  125. package/dist/tools/fastapply/core.cjs.map +1 -0
  126. package/dist/tools/fastapply/core.js +15 -0
  127. package/dist/tools/fastapply/core.js.map +1 -0
  128. package/dist/tools/fastapply/index.cjs +500 -0
  129. package/dist/tools/fastapply/index.cjs.map +1 -0
  130. package/dist/tools/fastapply/index.js +32 -0
  131. package/dist/tools/fastapply/index.js.map +1 -0
  132. package/dist/tools/fastapply/openai.cjs +353 -0
  133. package/dist/tools/fastapply/openai.cjs.map +1 -0
  134. package/dist/tools/fastapply/openai.js +21 -0
  135. package/dist/tools/fastapply/openai.js.map +1 -0
  136. package/dist/tools/fastapply/prompts.cjs +68 -0
  137. package/dist/tools/fastapply/prompts.cjs.map +1 -0
  138. package/dist/tools/fastapply/prompts.js +10 -0
  139. package/dist/tools/fastapply/prompts.js.map +1 -0
  140. package/dist/tools/fastapply/types.cjs +19 -0
  141. package/dist/tools/fastapply/types.cjs.map +1 -0
  142. package/dist/tools/fastapply/types.js +1 -0
  143. package/dist/tools/fastapply/types.js.map +1 -0
  144. package/dist/tools/fastapply/vercel.cjs +347 -0
  145. package/dist/tools/fastapply/vercel.cjs.map +1 -0
  146. package/dist/tools/fastapply/vercel.js +17 -0
  147. package/dist/tools/fastapply/vercel.js.map +1 -0
  148. package/dist/tools/index.cjs +500 -0
  149. package/dist/tools/index.cjs.map +1 -0
  150. package/dist/tools/index.js +32 -0
  151. package/dist/tools/index.js.map +1 -0
  152. package/dist/tools/modelrouter/core.cjs +286 -0
  153. package/dist/tools/modelrouter/core.cjs.map +1 -0
  154. package/dist/tools/modelrouter/core.js +13 -0
  155. package/dist/tools/modelrouter/core.js.map +1 -0
  156. package/dist/tools/modelrouter/index.cjs +286 -0
  157. package/dist/tools/modelrouter/index.cjs.map +1 -0
  158. package/dist/tools/modelrouter/index.js +13 -0
  159. package/dist/tools/modelrouter/index.js.map +1 -0
  160. package/dist/tools/modelrouter/types.cjs +19 -0
  161. package/dist/tools/modelrouter/types.cjs.map +1 -0
  162. package/dist/tools/modelrouter/types.js +1 -0
  163. package/dist/tools/modelrouter/types.js.map +1 -0
  164. package/dist/tools/utils/resilience.cjs +115 -0
  165. package/dist/tools/utils/resilience.cjs.map +1 -0
  166. package/dist/tools/utils/resilience.js +12 -0
  167. package/dist/tools/utils/resilience.js.map +1 -0
  168. package/package.json +159 -0
@@ -0,0 +1,1358 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // client.ts
31
+ var client_exports = {};
32
+ __export(client_exports, {
33
+ MorphClient: () => MorphClient
34
+ });
35
+ module.exports = __toCommonJS(client_exports);
36
+
37
+ // tools/fastapply/core.ts
38
+ var import_promises = require("fs/promises");
39
+ var import_path = require("path");
40
+ var import_diff = require("diff");
41
+
42
+ // tools/utils/resilience.ts
43
+ var DEFAULT_RETRY_CONFIG = {
44
+ maxRetries: 3,
45
+ initialDelay: 1e3,
46
+ maxDelay: 3e4,
47
+ backoffMultiplier: 2,
48
+ retryableErrors: ["ECONNREFUSED", "ETIMEDOUT", "ENOTFOUND"]
49
+ };
50
+ async function fetchWithRetry(url, options, retryConfig = {}) {
51
+ const {
52
+ maxRetries = DEFAULT_RETRY_CONFIG.maxRetries,
53
+ initialDelay = DEFAULT_RETRY_CONFIG.initialDelay,
54
+ maxDelay = DEFAULT_RETRY_CONFIG.maxDelay,
55
+ backoffMultiplier = DEFAULT_RETRY_CONFIG.backoffMultiplier,
56
+ retryableErrors = DEFAULT_RETRY_CONFIG.retryableErrors,
57
+ onRetry
58
+ } = retryConfig;
59
+ let lastError = null;
60
+ let delay = initialDelay;
61
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
62
+ try {
63
+ const response = await fetch(url, options);
64
+ if (response.status === 429 || response.status === 503) {
65
+ if (attempt < maxRetries) {
66
+ const retryAfter = response.headers.get("Retry-After");
67
+ const waitTime = retryAfter ? parseInt(retryAfter) * 1e3 : Math.min(delay, maxDelay);
68
+ const error = new Error(`HTTP ${response.status}: Retrying after ${waitTime}ms`);
69
+ if (onRetry) {
70
+ onRetry(attempt + 1, error);
71
+ }
72
+ await sleep(waitTime);
73
+ delay *= backoffMultiplier;
74
+ continue;
75
+ }
76
+ }
77
+ return response;
78
+ } catch (error) {
79
+ lastError = error;
80
+ const isRetryable = retryableErrors.some(
81
+ (errType) => lastError?.message?.includes(errType)
82
+ );
83
+ if (!isRetryable || attempt === maxRetries) {
84
+ throw lastError;
85
+ }
86
+ const waitTime = Math.min(delay, maxDelay);
87
+ if (onRetry) {
88
+ onRetry(attempt + 1, lastError);
89
+ }
90
+ await sleep(waitTime);
91
+ delay *= backoffMultiplier;
92
+ }
93
+ }
94
+ throw lastError || new Error("Max retries exceeded");
95
+ }
96
+ async function withTimeout(promise, timeoutMs, errorMessage) {
97
+ let timeoutId;
98
+ const timeoutPromise = new Promise((_, reject) => {
99
+ timeoutId = setTimeout(() => {
100
+ reject(new Error(errorMessage || `Operation timed out after ${timeoutMs}ms`));
101
+ }, timeoutMs);
102
+ });
103
+ try {
104
+ const result = await Promise.race([promise, timeoutPromise]);
105
+ clearTimeout(timeoutId);
106
+ return result;
107
+ } catch (error) {
108
+ clearTimeout(timeoutId);
109
+ throw error;
110
+ }
111
+ }
112
+ function sleep(ms) {
113
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
114
+ }
115
+
116
+ // tools/fastapply/core.ts
117
+ var DEFAULT_CONFIG = {
118
+ morphApiUrl: "https://api.morphllm.com",
119
+ baseDir: process.cwd(),
120
+ generateUdiff: true,
121
+ autoWrite: true,
122
+ timeout: 3e4,
123
+ debug: false
124
+ };
125
+ var FastApplyClient = class {
126
+ config;
127
+ constructor(config = {}) {
128
+ this.config = {
129
+ morphApiKey: config.apiKey,
130
+ morphApiUrl: DEFAULT_CONFIG.morphApiUrl,
131
+ debug: config.debug,
132
+ timeout: config.timeout || DEFAULT_CONFIG.timeout,
133
+ retryConfig: config.retryConfig,
134
+ generateUdiff: DEFAULT_CONFIG.generateUdiff,
135
+ autoWrite: DEFAULT_CONFIG.autoWrite
136
+ };
137
+ }
138
+ /**
139
+ * Execute a file edit operation
140
+ *
141
+ * @param input - Edit parameters including filepath, instructions, and code_edit
142
+ * @param overrides - Optional config overrides for this operation
143
+ * @returns Edit result with success status and changes
144
+ */
145
+ async execute(input, overrides) {
146
+ return executeEditFile(input, { ...this.config, ...overrides });
147
+ }
148
+ };
149
+ function generateUdiff(original, modified, filepath) {
150
+ return (0, import_diff.createTwoFilesPatch)(
151
+ filepath,
152
+ filepath,
153
+ original,
154
+ modified,
155
+ "Original",
156
+ "Modified"
157
+ );
158
+ }
159
+ function countChanges(original, modified) {
160
+ const diff = generateUdiff(original, modified, "file");
161
+ const lines = diff.split("\n");
162
+ let linesAdded = 0;
163
+ let linesRemoved = 0;
164
+ for (const line of lines) {
165
+ if (line.startsWith("+") && !line.startsWith("+++")) {
166
+ linesAdded++;
167
+ } else if (line.startsWith("-") && !line.startsWith("---")) {
168
+ linesRemoved++;
169
+ }
170
+ }
171
+ const linesModified = Math.min(linesAdded, linesRemoved);
172
+ return {
173
+ linesAdded: linesAdded - linesModified,
174
+ linesRemoved: linesRemoved - linesModified,
175
+ linesModified
176
+ };
177
+ }
178
+ async function callMorphAPI(originalCode, codeEdit, instructions, filepath, config) {
179
+ const apiKey = config.morphApiKey || process.env.MORPH_API_KEY;
180
+ const apiUrl = config.morphApiUrl || DEFAULT_CONFIG.morphApiUrl;
181
+ const timeout = config.timeout || DEFAULT_CONFIG.timeout;
182
+ const debug = config.debug || false;
183
+ if (!apiKey) {
184
+ throw new Error(
185
+ "Morph API key not found. Set MORPH_API_KEY environment variable or pass morphApiKey in config."
186
+ );
187
+ }
188
+ const message = `<instruction>${instructions}</instruction>
189
+ <code>${originalCode}</code>
190
+ <update>${codeEdit}</update>`;
191
+ if (debug) {
192
+ console.log(`[FastApply] Calling ${apiUrl}/v1/chat/completions`);
193
+ console.log(`[FastApply] File: ${filepath}, Instructions: ${instructions.slice(0, 60)}...`);
194
+ console.log(`[FastApply] Original: ${originalCode.length} chars, Edit: ${codeEdit.length} chars`);
195
+ }
196
+ const startTime = Date.now();
197
+ const fetchPromise = fetchWithRetry(
198
+ `${apiUrl}/v1/chat/completions`,
199
+ {
200
+ method: "POST",
201
+ headers: {
202
+ "Content-Type": "application/json",
203
+ "Authorization": `Bearer ${apiKey}`
204
+ },
205
+ body: JSON.stringify({
206
+ model: "morph-v3-fast",
207
+ messages: [{ role: "user", content: message }]
208
+ })
209
+ },
210
+ config.retryConfig
211
+ );
212
+ const response = await withTimeout(
213
+ fetchPromise,
214
+ timeout,
215
+ `Morph API request timed out after ${timeout}ms`
216
+ );
217
+ if (!response.ok) {
218
+ const error = await response.text();
219
+ if (debug) console.error(`[FastApply] API error: ${response.status} - ${error}`);
220
+ throw new Error(`Morph API error (${response.status}): ${error}`);
221
+ }
222
+ const data = await response.json();
223
+ const elapsed = Date.now() - startTime;
224
+ if (debug) {
225
+ console.log(`[FastApply] \u2705 Success in ${elapsed}ms, merged: ${data.choices[0].message.content.length} chars`);
226
+ }
227
+ return data.choices[0].message.content;
228
+ }
229
+ async function executeEditFile(input, config = {}) {
230
+ const baseDir = config.baseDir || DEFAULT_CONFIG.baseDir;
231
+ const fullPath = (0, import_path.resolve)((0, import_path.join)(baseDir, input.target_filepath));
232
+ const debug = config.debug || false;
233
+ const relativePath = (0, import_path.relative)(baseDir, fullPath);
234
+ if (relativePath.startsWith("..") || fullPath === baseDir) {
235
+ return {
236
+ success: false,
237
+ filepath: input.target_filepath,
238
+ changes: { linesAdded: 0, linesRemoved: 0, linesModified: 0 },
239
+ error: `Invalid filepath: '${input.target_filepath}' is outside baseDir`
240
+ };
241
+ }
242
+ try {
243
+ if (debug) console.log(`[FastApply] Reading file: ${input.target_filepath}`);
244
+ const originalCode = await (0, import_promises.readFile)(fullPath, "utf-8");
245
+ const mergedCode = await callMorphAPI(originalCode, input.code_edit, input.instructions, input.target_filepath, config);
246
+ const udiff = config.generateUdiff !== false ? generateUdiff(originalCode, mergedCode, input.target_filepath) : void 0;
247
+ if (config.autoWrite !== false) {
248
+ await (0, import_promises.writeFile)(fullPath, mergedCode, "utf-8");
249
+ if (debug) console.log(`[FastApply] Wrote ${mergedCode.length} chars to ${input.target_filepath}`);
250
+ }
251
+ const changes = countChanges(originalCode, mergedCode);
252
+ return {
253
+ success: true,
254
+ filepath: input.target_filepath,
255
+ udiff,
256
+ changes
257
+ };
258
+ } catch (error) {
259
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
260
+ if (debug) console.error(`[FastApply] Error: ${errorMessage}`);
261
+ return {
262
+ success: false,
263
+ filepath: input.target_filepath,
264
+ changes: { linesAdded: 0, linesRemoved: 0, linesModified: 0 },
265
+ error: errorMessage
266
+ };
267
+ }
268
+ }
269
+
270
+ // tools/codebase_search/core.ts
271
+ var CodebaseSearchClient = class {
272
+ config;
273
+ constructor(config = {}) {
274
+ this.config = {
275
+ apiKey: config.apiKey,
276
+ searchUrl: process.env.MORPH_SEARCH_URL || "http://embedrerank.morphllm.com:8081",
277
+ debug: config.debug,
278
+ timeout: config.timeout || 3e4,
279
+ retryConfig: config.retryConfig
280
+ };
281
+ }
282
+ /**
283
+ * Execute a semantic code search
284
+ *
285
+ * @param input - Search parameters including query, repoId, and target directories
286
+ * @param overrides - Optional config overrides for this operation
287
+ * @returns Search results with ranked code matches
288
+ */
289
+ async search(input, overrides) {
290
+ return executeCodebaseSearch(
291
+ {
292
+ query: input.query,
293
+ target_directories: input.target_directories,
294
+ explanation: input.explanation,
295
+ limit: input.limit
296
+ },
297
+ { ...this.config, repoId: input.repoId, ...overrides }
298
+ );
299
+ }
300
+ };
301
+ async function executeCodebaseSearch(input, config) {
302
+ const apiKey = config.apiKey || process.env.MORPH_API_KEY;
303
+ if (!apiKey) {
304
+ throw new Error("MORPH_API_KEY not found. Set environment variable or pass in config");
305
+ }
306
+ const searchUrl = config.searchUrl || process.env.MORPH_SEARCH_URL || "http://embedrerank.morphllm.com:8081";
307
+ const timeout = config.timeout || 3e4;
308
+ const debug = config.debug || false;
309
+ if (debug) {
310
+ console.log(`[CodebaseSearch] Query: "${input.query.slice(0, 60)}..." repo=${config.repoId}`);
311
+ console.log(`[CodebaseSearch] URL: ${searchUrl}/v1/codebase_search`);
312
+ }
313
+ const startTime = Date.now();
314
+ try {
315
+ const fetchPromise = fetchWithRetry(
316
+ `${searchUrl}/v1/codebase_search`,
317
+ {
318
+ method: "POST",
319
+ headers: {
320
+ "Content-Type": "application/json",
321
+ "Authorization": `Bearer ${apiKey}`
322
+ },
323
+ body: JSON.stringify({
324
+ query: input.query,
325
+ repoId: config.repoId,
326
+ targetDirectories: input.target_directories || [],
327
+ limit: input.limit || 10,
328
+ candidateLimit: 50
329
+ })
330
+ },
331
+ config.retryConfig
332
+ );
333
+ const response = await withTimeout(fetchPromise, timeout, `Codebase search timed out after ${timeout}ms`);
334
+ if (!response.ok) {
335
+ const errorText = await response.text();
336
+ if (debug) console.error(`[CodebaseSearch] Error: ${response.status} - ${errorText}`);
337
+ return {
338
+ success: false,
339
+ results: [],
340
+ stats: { totalResults: 0, candidatesRetrieved: 0, searchTimeMs: 0 },
341
+ error: `Search failed (${response.status}): ${errorText}`
342
+ };
343
+ }
344
+ const data = await response.json();
345
+ const elapsed = Date.now() - startTime;
346
+ if (debug) {
347
+ console.log(`[CodebaseSearch] \u2705 ${data.results?.length || 0} results in ${elapsed}ms`);
348
+ }
349
+ return {
350
+ success: true,
351
+ results: data.results || [],
352
+ stats: data.stats || { totalResults: 0, candidatesRetrieved: 0, searchTimeMs: elapsed }
353
+ };
354
+ } catch (error) {
355
+ if (debug) console.error(`[CodebaseSearch] Exception: ${error instanceof Error ? error.message : error}`);
356
+ return {
357
+ success: false,
358
+ results: [],
359
+ stats: { totalResults: 0, candidatesRetrieved: 0, searchTimeMs: 0 },
360
+ error: error instanceof Error ? error.message : "Unknown error"
361
+ };
362
+ }
363
+ }
364
+
365
+ // tools/browser/core.ts
366
+ var DEFAULT_CONFIG2 = {
367
+ apiUrl: process.env.MORPH_ENVIRONMENT === "DEV" ? "http://localhost:8000" : "https://browser.morphllm.com",
368
+ timeout: 12e4,
369
+ // 2 minutes for complex tasks
370
+ debug: false
371
+ };
372
+ var BrowserClient = class {
373
+ config;
374
+ constructor(config = {}) {
375
+ this.config = {
376
+ ...DEFAULT_CONFIG2,
377
+ ...config
378
+ };
379
+ }
380
+ /**
381
+ * Execute a browser automation task
382
+ */
383
+ async execute(input) {
384
+ return executeBrowserTask(input, this.config);
385
+ }
386
+ async createTask(input) {
387
+ if ("schema" in input) {
388
+ const taskInput = {
389
+ ...input,
390
+ structured_output: stringifyStructuredOutput(input.schema)
391
+ };
392
+ const result = await executeBrowserTask(taskInput, this.config);
393
+ return wrapTaskResponseWithSchema(result, this.config, input.schema);
394
+ } else {
395
+ const result = await executeBrowserTask(input, this.config);
396
+ return wrapTaskResponse(result, this.config);
397
+ }
398
+ }
399
+ /**
400
+ * Execute task with recording and wait for video to be ready
401
+ */
402
+ async executeWithRecording(input) {
403
+ return executeWithRecording(input, this.config);
404
+ }
405
+ /**
406
+ * Get recording status and URLs
407
+ */
408
+ async getRecording(recordingId) {
409
+ return getRecording(recordingId, this.config);
410
+ }
411
+ /**
412
+ * Wait for recording to complete with automatic polling
413
+ */
414
+ async waitForRecording(recordingId, options) {
415
+ return waitForRecording(recordingId, this.config, options);
416
+ }
417
+ /**
418
+ * Get errors from recording with screenshots
419
+ */
420
+ async getErrors(recordingId) {
421
+ return getErrors(recordingId, this.config);
422
+ }
423
+ /**
424
+ * Check if browser worker service is healthy
425
+ */
426
+ async checkHealth() {
427
+ return checkHealth(this.config);
428
+ }
429
+ };
430
+ async function executeBrowserTask(input, config = {}) {
431
+ const apiUrl = config.apiUrl || DEFAULT_CONFIG2.apiUrl;
432
+ const timeout = config.timeout || DEFAULT_CONFIG2.timeout;
433
+ const debug = config.debug || false;
434
+ if (!input.task || input.task.trim().length === 0) {
435
+ return { success: false, error: "Task description is required" };
436
+ }
437
+ if (input.max_steps !== void 0 && (input.max_steps < 1 || input.max_steps > 50)) {
438
+ return { success: false, error: "max_steps must be between 1 and 50" };
439
+ }
440
+ if (debug) {
441
+ console.log(`[Browser] Task: "${input.task.slice(0, 60)}..." url=${input.url || "none"} maxSteps=${input.max_steps ?? 10}`);
442
+ console.log(`[Browser] Recording: ${input.record_video ? "yes" : "no"} | Calling ${apiUrl}/browser-task`);
443
+ }
444
+ const startTime = Date.now();
445
+ try {
446
+ const headers = { "Content-Type": "application/json" };
447
+ if (config.apiKey) headers["Authorization"] = `Bearer ${config.apiKey}`;
448
+ const fetchPromise = fetchWithRetry(
449
+ `${apiUrl}/browser-task`,
450
+ {
451
+ method: "POST",
452
+ headers,
453
+ body: JSON.stringify({
454
+ task: input.task,
455
+ url: input.url,
456
+ max_steps: input.max_steps ?? 10,
457
+ model: input.model ?? "morph-computer-use-v0",
458
+ viewport_width: input.viewport_width ?? 1280,
459
+ viewport_height: input.viewport_height ?? 720,
460
+ repo_id: input.repo_id,
461
+ commit_id: input.commit_id,
462
+ record_video: input.record_video ?? false,
463
+ video_width: input.video_width ?? input.viewport_width ?? 1280,
464
+ video_height: input.video_height ?? input.viewport_height ?? 720,
465
+ structured_output: input.structured_output
466
+ })
467
+ },
468
+ config.retryConfig
469
+ );
470
+ const response = await withTimeout(
471
+ fetchPromise,
472
+ timeout,
473
+ `Browser task timed out after ${timeout}ms. Consider increasing timeout or reducing max_steps.`
474
+ );
475
+ if (!response.ok) {
476
+ const errorText = await response.text().catch(() => response.statusText);
477
+ if (debug) console.error(`[Browser] Error: ${response.status} - ${errorText}`);
478
+ throw new Error(`HTTP ${response.status}: ${errorText}`);
479
+ }
480
+ const result = await response.json();
481
+ const elapsed = Date.now() - startTime;
482
+ if (debug) {
483
+ console.log(`[Browser] \u2705 ${result.success ? "Success" : "Failed"} in ${elapsed}ms | steps=${result.steps_taken ?? 0} recordingId=${result.recording_id ?? "none"}`);
484
+ }
485
+ return result;
486
+ } catch (error) {
487
+ if (error instanceof Error) {
488
+ if (error.message.includes("ECONNREFUSED") || error.message.includes("fetch failed")) {
489
+ return {
490
+ success: false,
491
+ error: `Cannot connect to browser worker at ${apiUrl}. Ensure the service is running.`
492
+ };
493
+ }
494
+ return {
495
+ success: false,
496
+ error: error.message
497
+ };
498
+ }
499
+ return {
500
+ success: false,
501
+ error: String(error)
502
+ };
503
+ }
504
+ }
505
+ async function getRecording(recordingId, config = {}) {
506
+ const apiUrl = config.apiUrl || DEFAULT_CONFIG2.apiUrl;
507
+ const debug = config.debug || false;
508
+ if (!config.apiKey) {
509
+ throw new Error("API key required for getRecording");
510
+ }
511
+ if (debug) console.log(`[Browser] getRecording: ${recordingId}`);
512
+ const response = await fetch(`${apiUrl}/recordings/${recordingId}`, {
513
+ method: "GET",
514
+ headers: { "Authorization": `Bearer ${config.apiKey}` }
515
+ });
516
+ if (!response.ok) {
517
+ const errorText = await response.text().catch(() => response.statusText);
518
+ if (debug) console.error(`[Browser] getRecording error: ${response.status} - ${errorText}`);
519
+ throw new Error(`HTTP ${response.status}: ${errorText}`);
520
+ }
521
+ const recording = await response.json();
522
+ if (debug) console.log(`[Browser] Recording status: ${recording.status}`);
523
+ return recording;
524
+ }
525
+ async function waitForRecording(recordingId, config = {}, options = {}) {
526
+ const timeout = options.timeout ?? 6e4;
527
+ const pollInterval = options.pollInterval ?? 2e3;
528
+ const startTime = Date.now();
529
+ while (Date.now() - startTime < timeout) {
530
+ const status = await getRecording(recordingId, config);
531
+ if (status.status === "COMPLETED" || status.status === "ERROR") {
532
+ return status;
533
+ }
534
+ await new Promise((resolve2) => setTimeout(resolve2, pollInterval));
535
+ }
536
+ throw new Error(`Recording timeout after ${timeout}ms - status still pending`);
537
+ }
538
+ async function executeWithRecording(input, config = {}) {
539
+ const taskResult = await executeBrowserTask(input, config);
540
+ if (taskResult.recording_id) {
541
+ try {
542
+ const recording = await waitForRecording(
543
+ taskResult.recording_id,
544
+ config,
545
+ { timeout: 6e4, pollInterval: 2e3 }
546
+ );
547
+ return {
548
+ ...taskResult,
549
+ recording
550
+ };
551
+ } catch (error) {
552
+ return {
553
+ ...taskResult,
554
+ recording: {
555
+ id: taskResult.recording_id,
556
+ status: "ERROR",
557
+ error: error instanceof Error ? error.message : String(error),
558
+ created_at: (/* @__PURE__ */ new Date()).toISOString()
559
+ }
560
+ };
561
+ }
562
+ }
563
+ return taskResult;
564
+ }
565
+ async function getErrors(recordingId, config = {}) {
566
+ const apiUrl = config.apiUrl || DEFAULT_CONFIG2.apiUrl;
567
+ const debug = config.debug || false;
568
+ if (!config.apiKey) {
569
+ throw new Error("API key required for getErrors");
570
+ }
571
+ if (debug) console.log(`[Browser] getErrors: ${recordingId}`);
572
+ const response = await fetch(`${apiUrl}/recordings/${recordingId}/errors`, {
573
+ method: "GET",
574
+ headers: { "Authorization": `Bearer ${config.apiKey}` }
575
+ });
576
+ if (!response.ok) {
577
+ const errorText = await response.text().catch(() => response.statusText);
578
+ if (debug) console.error(`[Browser] getErrors error: ${response.status} - ${errorText}`);
579
+ throw new Error(`HTTP ${response.status}: ${errorText}`);
580
+ }
581
+ const errors = await response.json();
582
+ if (debug) console.log(`[Browser] Found ${errors.total_errors} errors`);
583
+ return errors;
584
+ }
585
+ function stringifyStructuredOutput(schema) {
586
+ try {
587
+ return JSON.stringify({
588
+ type: "object",
589
+ description: "Zod schema definition (Zod v3)",
590
+ zodDef: schema._def
591
+ });
592
+ } catch (error) {
593
+ console.warn("[Browser] Failed to serialize Zod schema:", error);
594
+ return JSON.stringify({
595
+ type: "object",
596
+ description: "Schema serialization failed"
597
+ });
598
+ }
599
+ }
600
+ function parseStructuredTaskOutput(result, schema) {
601
+ if (!result.output) {
602
+ return { ...result, parsed: null };
603
+ }
604
+ try {
605
+ const parsed = JSON.parse(result.output);
606
+ const validated = schema.parse(parsed);
607
+ return { ...result, parsed: validated };
608
+ } catch (error) {
609
+ if (error instanceof SyntaxError) {
610
+ return { ...result, parsed: null };
611
+ }
612
+ throw error;
613
+ }
614
+ }
615
+ async function getTaskStatus(taskId, config) {
616
+ const apiUrl = config.apiUrl || DEFAULT_CONFIG2.apiUrl;
617
+ const debug = config.debug || false;
618
+ if (debug) console.log(`[Browser] getTaskStatus: ${taskId}`);
619
+ const headers = {};
620
+ if (config.apiKey) headers["Authorization"] = `Bearer ${config.apiKey}`;
621
+ const response = await fetch(`${apiUrl}/tasks/${taskId}`, {
622
+ method: "GET",
623
+ headers
624
+ });
625
+ if (!response.ok) {
626
+ const errorText = await response.text().catch(() => response.statusText);
627
+ if (debug) console.error(`[Browser] getTaskStatus error: ${response.status} - ${errorText}`);
628
+ throw new Error(`HTTP ${response.status}: ${errorText}`);
629
+ }
630
+ const result = await response.json();
631
+ if (debug) console.log(`[Browser] Task status: ${result.status}`);
632
+ return result;
633
+ }
634
+ function generateLiveUrl(taskId, config) {
635
+ const apiUrl = config.apiUrl || DEFAULT_CONFIG2.apiUrl;
636
+ const baseUrl = apiUrl.replace("/api", "");
637
+ return `${baseUrl}/tasks/${taskId}/live`;
638
+ }
639
+ async function pollTaskUntilComplete(taskId, config, pollConfig = {}) {
640
+ const interval = pollConfig.interval ?? 2e3;
641
+ const timeout = pollConfig.timeout ?? 3e5;
642
+ const startTime = Date.now();
643
+ while (Date.now() - startTime < timeout) {
644
+ const status = await getTaskStatus(taskId, config);
645
+ if (status.status === "completed" || status.status === "failed") {
646
+ return status;
647
+ }
648
+ await new Promise((resolve2) => setTimeout(resolve2, interval));
649
+ }
650
+ throw new Error(`Task polling timeout after ${timeout}ms`);
651
+ }
652
+ function wrapTaskResponse(result, config) {
653
+ if (!result.task_id) {
654
+ throw new Error("task_id is required to wrap response");
655
+ }
656
+ return {
657
+ ...result,
658
+ task_id: result.task_id,
659
+ liveUrl: generateLiveUrl(result.task_id, config),
660
+ complete: async (pollConfig) => {
661
+ return pollTaskUntilComplete(result.task_id, config, pollConfig);
662
+ }
663
+ };
664
+ }
665
+ function wrapTaskResponseWithSchema(result, config, schema) {
666
+ if (!result.task_id) {
667
+ throw new Error("task_id is required to wrap response");
668
+ }
669
+ const parsed = result.output ? parseStructuredTaskOutput(result, schema) : { ...result, parsed: null };
670
+ return {
671
+ ...parsed,
672
+ task_id: result.task_id,
673
+ liveUrl: generateLiveUrl(result.task_id, config),
674
+ complete: async (pollConfig) => {
675
+ const finalResult = await pollTaskUntilComplete(result.task_id, config, pollConfig);
676
+ return parseStructuredTaskOutput(finalResult, schema);
677
+ }
678
+ };
679
+ }
680
+ async function checkHealth(config = {}) {
681
+ const apiUrl = config.apiUrl || DEFAULT_CONFIG2.apiUrl;
682
+ try {
683
+ const response = await fetch(`${apiUrl}/health`, {
684
+ method: "GET",
685
+ headers: config.apiKey ? { "Authorization": `Bearer ${config.apiKey}` } : {}
686
+ });
687
+ if (!response.ok) {
688
+ throw new Error(`HTTP ${response.status}`);
689
+ }
690
+ const data = await response.json();
691
+ return {
692
+ ok: true,
693
+ google_configured: data.google_configured ?? false,
694
+ database_configured: data.database_configured ?? false,
695
+ s3_configured: data.s3_configured ?? false
696
+ };
697
+ } catch (error) {
698
+ return {
699
+ ok: false,
700
+ google_configured: false,
701
+ database_configured: false,
702
+ s3_configured: false,
703
+ error: error instanceof Error ? error.message : String(error)
704
+ };
705
+ }
706
+ }
707
+
708
+ // git/client.ts
709
+ var import_isomorphic_git = __toESM(require("isomorphic-git"), 1);
710
+ var import_node = __toESM(require("isomorphic-git/http/node"), 1);
711
+ var import_fs = __toESM(require("fs"), 1);
712
+ var DEFAULT_PROXY_URL = "https://repos.morphllm.com";
713
+ var MorphGit = class {
714
+ apiKey;
715
+ proxyUrl;
716
+ constructor(config) {
717
+ if (!config.apiKey) {
718
+ throw new Error("API key is required. Get one at https://morphllm.com/dashboard");
719
+ }
720
+ if (!config.apiKey.startsWith("sk-") && !config.apiKey.startsWith("morph-")) {
721
+ throw new Error("Invalid API key format. Expected: sk-... or morph-...");
722
+ }
723
+ this.apiKey = config.apiKey;
724
+ this.proxyUrl = config.proxyUrl || DEFAULT_PROXY_URL;
725
+ }
726
+ /**
727
+ * Get auth callback for isomorphic-git operations
728
+ * @private
729
+ */
730
+ getAuthCallback() {
731
+ return () => ({
732
+ username: "morph",
733
+ password: this.apiKey
734
+ });
735
+ }
736
+ /**
737
+ * Initialize a new repository
738
+ * Creates the repo in the database and in the git provider
739
+ *
740
+ * @example
741
+ * ```ts
742
+ * await morphGit.init({
743
+ * repoId: 'my-project',
744
+ * dir: './my-project',
745
+ * defaultBranch: 'main'
746
+ * });
747
+ * ```
748
+ */
749
+ async init(options) {
750
+ const { repoId, dir, defaultBranch = "main" } = options;
751
+ const response = await fetch(`${this.proxyUrl}/v1/repos`, {
752
+ method: "POST",
753
+ headers: {
754
+ "Authorization": `Bearer ${this.apiKey}`,
755
+ "Content-Type": "application/json"
756
+ },
757
+ body: JSON.stringify({
758
+ repoId,
759
+ name: repoId,
760
+ defaultBranch
761
+ })
762
+ });
763
+ if (!response.ok) {
764
+ const error = await response.text();
765
+ throw new Error(`Failed to create repository: ${error}`);
766
+ }
767
+ await import_isomorphic_git.default.init({
768
+ fs: import_fs.default,
769
+ dir,
770
+ defaultBranch
771
+ });
772
+ await import_isomorphic_git.default.addRemote({
773
+ fs: import_fs.default,
774
+ dir,
775
+ remote: "origin",
776
+ url: `${this.proxyUrl}/v1/repos/${repoId}`
777
+ });
778
+ console.log(`\u2713 Repository '${repoId}' initialized`);
779
+ }
780
+ /**
781
+ * Clone a repository from Morph repos
782
+ *
783
+ * @example
784
+ * ```ts
785
+ * await morphGit.clone({
786
+ * repoId: 'my-project',
787
+ * dir: './my-project'
788
+ * });
789
+ * ```
790
+ */
791
+ async clone(options) {
792
+ const { repoId, dir, branch = "main", depth, singleBranch = true } = options;
793
+ await import_isomorphic_git.default.clone({
794
+ fs: import_fs.default,
795
+ http: import_node.default,
796
+ dir,
797
+ corsProxy: this.proxyUrl,
798
+ url: `${this.proxyUrl}/v1/repos/${repoId}`,
799
+ ref: branch,
800
+ singleBranch,
801
+ depth,
802
+ onAuth: this.getAuthCallback()
803
+ });
804
+ }
805
+ /**
806
+ * Push changes to remote repository
807
+ *
808
+ * @example
809
+ * ```ts
810
+ * await morphGit.push({ dir: './my-project' });
811
+ * ```
812
+ */
813
+ async push(options) {
814
+ const { dir, remote = "origin", branch } = options;
815
+ await import_isomorphic_git.default.push({
816
+ fs: import_fs.default,
817
+ http: import_node.default,
818
+ dir,
819
+ remote,
820
+ ref: branch,
821
+ onAuth: this.getAuthCallback()
822
+ });
823
+ }
824
+ /**
825
+ * Pull changes from remote repository
826
+ *
827
+ * @example
828
+ * ```ts
829
+ * await morphGit.pull({ dir: './my-project' });
830
+ * ```
831
+ */
832
+ async pull(options) {
833
+ const { dir, remote = "origin", branch } = options;
834
+ await import_isomorphic_git.default.pull({
835
+ fs: import_fs.default,
836
+ http: import_node.default,
837
+ dir,
838
+ remote,
839
+ ref: branch,
840
+ onAuth: this.getAuthCallback(),
841
+ author: {
842
+ name: "Morph Agent",
843
+ email: "agent@morph.com"
844
+ }
845
+ });
846
+ }
847
+ /**
848
+ * Stage a file for commit
849
+ *
850
+ * @example
851
+ * ```ts
852
+ * await morphGit.add({
853
+ * dir: './my-project',
854
+ * filepath: 'src/app.ts'
855
+ * });
856
+ * ```
857
+ */
858
+ async add(options) {
859
+ const { dir, filepath } = options;
860
+ await import_isomorphic_git.default.add({
861
+ fs: import_fs.default,
862
+ dir,
863
+ filepath
864
+ });
865
+ }
866
+ /**
867
+ * Remove a file from staging
868
+ *
869
+ * @example
870
+ * ```ts
871
+ * await morphGit.remove({
872
+ * dir: './my-project',
873
+ * filepath: 'src/old-file.ts'
874
+ * });
875
+ * ```
876
+ */
877
+ async remove(options) {
878
+ const { dir, filepath } = options;
879
+ await import_isomorphic_git.default.remove({
880
+ fs: import_fs.default,
881
+ dir,
882
+ filepath
883
+ });
884
+ }
885
+ /**
886
+ * Commit staged changes
887
+ *
888
+ * @example
889
+ * ```ts
890
+ * await morphGit.commit({
891
+ * dir: './my-project',
892
+ * message: 'Add new feature',
893
+ * author: {
894
+ * name: 'AI Agent',
895
+ * email: 'ai@example.com'
896
+ * }
897
+ * });
898
+ * ```
899
+ */
900
+ async commit(options) {
901
+ const { dir, message, author } = options;
902
+ const commitAuthor = author || {
903
+ name: "Morph SDK",
904
+ email: "sdk@morphllm.com"
905
+ };
906
+ const sha = await import_isomorphic_git.default.commit({
907
+ fs: import_fs.default,
908
+ dir,
909
+ message,
910
+ author: commitAuthor
911
+ });
912
+ return sha;
913
+ }
914
+ /**
915
+ * Get status of a file
916
+ *
917
+ * @example
918
+ * ```ts
919
+ * const status = await morphGit.status({
920
+ * dir: './my-project',
921
+ * filepath: 'src/app.ts'
922
+ * });
923
+ * console.log(status); // 'modified', '*added', etc.
924
+ * ```
925
+ */
926
+ async status(options) {
927
+ const { dir, filepath } = options;
928
+ if (!filepath) {
929
+ throw new Error("filepath is required for status check");
930
+ }
931
+ const status = await import_isomorphic_git.default.status({
932
+ fs: import_fs.default,
933
+ dir,
934
+ filepath
935
+ });
936
+ return status;
937
+ }
938
+ /**
939
+ * Get commit history
940
+ *
941
+ * @example
942
+ * ```ts
943
+ * const commits = await morphGit.log({
944
+ * dir: './my-project',
945
+ * depth: 10
946
+ * });
947
+ * ```
948
+ */
949
+ async log(options) {
950
+ const { dir, depth, ref } = options;
951
+ const commits = await import_isomorphic_git.default.log({
952
+ fs: import_fs.default,
953
+ dir,
954
+ depth,
955
+ ref
956
+ });
957
+ return commits;
958
+ }
959
+ /**
960
+ * Checkout a branch or commit
961
+ *
962
+ * @example
963
+ * ```ts
964
+ * await morphGit.checkout({
965
+ * dir: './my-project',
966
+ * ref: 'feature-branch'
967
+ * });
968
+ * ```
969
+ */
970
+ async checkout(options) {
971
+ const { dir, ref } = options;
972
+ await import_isomorphic_git.default.checkout({
973
+ fs: import_fs.default,
974
+ dir,
975
+ ref
976
+ });
977
+ }
978
+ /**
979
+ * Create a new branch
980
+ *
981
+ * @example
982
+ * ```ts
983
+ * await morphGit.branch({
984
+ * dir: './my-project',
985
+ * name: 'feature-branch',
986
+ * checkout: true
987
+ * });
988
+ * ```
989
+ */
990
+ async branch(options) {
991
+ const { dir, name, checkout = false } = options;
992
+ await import_isomorphic_git.default.branch({
993
+ fs: import_fs.default,
994
+ dir,
995
+ ref: name,
996
+ checkout
997
+ });
998
+ }
999
+ /**
1000
+ * List all branches
1001
+ *
1002
+ * @example
1003
+ * ```ts
1004
+ * const branches = await morphGit.listBranches({
1005
+ * dir: './my-project'
1006
+ * });
1007
+ * ```
1008
+ */
1009
+ async listBranches(options) {
1010
+ const { dir } = options;
1011
+ const branches = await import_isomorphic_git.default.listBranches({
1012
+ fs: import_fs.default,
1013
+ dir
1014
+ });
1015
+ return branches;
1016
+ }
1017
+ /**
1018
+ * Get the current branch name
1019
+ *
1020
+ * @example
1021
+ * ```ts
1022
+ * const branch = await morphGit.currentBranch({
1023
+ * dir: './my-project'
1024
+ * });
1025
+ * ```
1026
+ */
1027
+ async currentBranch(options) {
1028
+ const { dir } = options;
1029
+ const branch = await import_isomorphic_git.default.currentBranch({
1030
+ fs: import_fs.default,
1031
+ dir
1032
+ });
1033
+ return branch || void 0;
1034
+ }
1035
+ /**
1036
+ * Get list of changed files (similar to git diff --name-only)
1037
+ *
1038
+ * @example
1039
+ * ```ts
1040
+ * const changes = await morphGit.statusMatrix({
1041
+ * dir: './my-project'
1042
+ * });
1043
+ * ```
1044
+ */
1045
+ async statusMatrix(options) {
1046
+ const { dir } = options;
1047
+ const matrix = await import_isomorphic_git.default.statusMatrix({
1048
+ fs: import_fs.default,
1049
+ dir
1050
+ });
1051
+ return matrix.map(([filepath, HEADStatus, workdirStatus, stageStatus]) => {
1052
+ let status = "unmodified";
1053
+ if (HEADStatus === 1 && workdirStatus === 2 && stageStatus === 2) {
1054
+ status = "modified";
1055
+ } else if (HEADStatus === 1 && workdirStatus === 2 && stageStatus === 1) {
1056
+ status = "*modified";
1057
+ } else if (HEADStatus === 0 && workdirStatus === 2 && stageStatus === 2) {
1058
+ status = "added";
1059
+ } else if (HEADStatus === 0 && workdirStatus === 2 && stageStatus === 0) {
1060
+ status = "*added";
1061
+ } else if (HEADStatus === 1 && workdirStatus === 0 && stageStatus === 0) {
1062
+ status = "deleted";
1063
+ } else if (HEADStatus === 1 && workdirStatus === 0 && stageStatus === 1) {
1064
+ status = "*deleted";
1065
+ } else if (HEADStatus === 1 && workdirStatus === 1 && stageStatus === 1) {
1066
+ status = "unmodified";
1067
+ } else if (HEADStatus === 0 && workdirStatus === 0 && stageStatus === 0) {
1068
+ status = "absent";
1069
+ }
1070
+ return {
1071
+ filepath,
1072
+ status
1073
+ };
1074
+ });
1075
+ }
1076
+ /**
1077
+ * Get the current commit hash
1078
+ *
1079
+ * @example
1080
+ * ```ts
1081
+ * const hash = await morphGit.resolveRef({
1082
+ * dir: './my-project',
1083
+ * ref: 'HEAD'
1084
+ * });
1085
+ * ```
1086
+ */
1087
+ async resolveRef(options) {
1088
+ const { dir, ref } = options;
1089
+ const oid = await import_isomorphic_git.default.resolveRef({
1090
+ fs: import_fs.default,
1091
+ dir,
1092
+ ref
1093
+ });
1094
+ return oid;
1095
+ }
1096
+ };
1097
+
1098
+ // git/index.ts
1099
+ var import_isomorphic_git2 = __toESM(require("isomorphic-git"), 1);
1100
+ var import_node2 = __toESM(require("isomorphic-git/http/node"), 1);
1101
+
1102
+ // tools/modelrouter/core.ts
1103
+ var DEFAULT_CONFIG3 = {
1104
+ apiUrl: "https://api.morphllm.com",
1105
+ timeout: 1e4,
1106
+ // 10 seconds
1107
+ debug: false
1108
+ };
1109
+ var MODEL_MAPPINGS = {
1110
+ openai: {
1111
+ balanced: {
1112
+ easy: "gpt-5-mini",
1113
+ medium: "gpt-5-low",
1114
+ hard: "gpt-5-medium",
1115
+ "needs-info": "gpt-5-mini"
1116
+ },
1117
+ aggressive: {
1118
+ easy: "gpt-5-low",
1119
+ medium: "gpt-5-medium",
1120
+ hard: "gpt-5-high",
1121
+ "needs-info": "gpt-5-mini"
1122
+ }
1123
+ },
1124
+ anthropic: {
1125
+ balanced: {
1126
+ easy: "claude-4.5-haiku",
1127
+ medium: "claude-4.5-haiku",
1128
+ hard: "claude-4.5-sonnet",
1129
+ "needs-info": "claude-4.5-haiku"
1130
+ },
1131
+ aggressive: {
1132
+ easy: "claude-4.5-haiku",
1133
+ medium: "claude-4.5-sonnet",
1134
+ hard: "claude-4.5-sonnet",
1135
+ "needs-info": "claude-4.5-haiku"
1136
+ }
1137
+ },
1138
+ gemini: {
1139
+ balanced: {
1140
+ easy: "gemini-2.5-flash",
1141
+ medium: "gemini-2.5-flash",
1142
+ hard: "gemini-2.5-pro",
1143
+ "needs-info": "gemini-2.5-flash"
1144
+ },
1145
+ aggressive: {
1146
+ easy: "gemini-2.5-flash",
1147
+ medium: "gemini-2.5-pro",
1148
+ hard: "gemini-2.5-pro",
1149
+ "needs-info": "gemini-2.5-flash"
1150
+ }
1151
+ }
1152
+ };
1153
+ var BaseRouter = class {
1154
+ config;
1155
+ provider;
1156
+ constructor(provider, config = {}) {
1157
+ this.provider = provider;
1158
+ this.config = {
1159
+ apiKey: config.apiKey,
1160
+ apiUrl: config.apiUrl || DEFAULT_CONFIG3.apiUrl,
1161
+ timeout: config.timeout || DEFAULT_CONFIG3.timeout,
1162
+ debug: config.debug || DEFAULT_CONFIG3.debug,
1163
+ retryConfig: config.retryConfig
1164
+ };
1165
+ }
1166
+ /**
1167
+ * Map backend complexity classification to actual model name
1168
+ */
1169
+ mapComplexityToModel(complexity, mode) {
1170
+ const mapping = MODEL_MAPPINGS[this.provider][mode];
1171
+ return mapping[complexity];
1172
+ }
1173
+ /**
1174
+ * Select the optimal model for a given input and mode
1175
+ */
1176
+ async selectModel(input) {
1177
+ const mode = input.mode || "balanced";
1178
+ const apiKey = this.config.apiKey || process.env.MORPH_API_KEY;
1179
+ if (!apiKey) {
1180
+ throw new Error(
1181
+ "Morph API key is required. Set MORPH_API_KEY environment variable or pass apiKey in config."
1182
+ );
1183
+ }
1184
+ const url = `${this.config.apiUrl}/router/${this.provider}`;
1185
+ const payload = {
1186
+ input: input.input,
1187
+ mode
1188
+ };
1189
+ if (this.config.debug) {
1190
+ console.log(`[ModelRouter] Requesting ${this.provider} model selection:`, {
1191
+ mode,
1192
+ inputLength: input.input.length
1193
+ });
1194
+ }
1195
+ try {
1196
+ const fetchPromise = fetchWithRetry(
1197
+ url,
1198
+ {
1199
+ method: "POST",
1200
+ headers: {
1201
+ "Content-Type": "application/json",
1202
+ Authorization: `Bearer ${apiKey}`
1203
+ },
1204
+ body: JSON.stringify(payload)
1205
+ },
1206
+ this.config.retryConfig
1207
+ );
1208
+ const response = await withTimeout(
1209
+ fetchPromise,
1210
+ this.config.timeout,
1211
+ `Router API request timed out after ${this.config.timeout}ms`
1212
+ );
1213
+ if (!response.ok) {
1214
+ const errorText = await response.text();
1215
+ throw new Error(
1216
+ `Router API error (${response.status}): ${errorText || response.statusText}`
1217
+ );
1218
+ }
1219
+ const apiResult = await response.json();
1220
+ const actualModel = this.mapComplexityToModel(apiResult.model, mode);
1221
+ const result = {
1222
+ model: actualModel,
1223
+ reasoning: apiResult.reasoning
1224
+ };
1225
+ if (this.config.debug) {
1226
+ console.log(`[ModelRouter] Complexity: ${apiResult.model}, Selected model: ${actualModel}`);
1227
+ }
1228
+ return result;
1229
+ } catch (error) {
1230
+ if (this.config.debug) {
1231
+ console.error(`[ModelRouter] Error selecting model:`, error);
1232
+ }
1233
+ throw error;
1234
+ }
1235
+ }
1236
+ };
1237
+ var OpenAIRouter = class extends BaseRouter {
1238
+ constructor(config = {}) {
1239
+ super("openai", config);
1240
+ }
1241
+ /**
1242
+ * Select optimal GPT-5 model
1243
+ *
1244
+ * @param input - User input and mode
1245
+ * @returns Selected model name (gpt-5-mini | gpt-5-low | gpt-5-medium | gpt-5-high)
1246
+ */
1247
+ async selectModel(input) {
1248
+ return super.selectModel(input);
1249
+ }
1250
+ };
1251
+ var AnthropicRouter = class extends BaseRouter {
1252
+ constructor(config = {}) {
1253
+ super("anthropic", config);
1254
+ }
1255
+ /**
1256
+ * Select optimal Claude model
1257
+ *
1258
+ * @param input - User input and mode
1259
+ * @returns Selected model name (claude-4.5-haiku | claude-4.5-sonnet)
1260
+ */
1261
+ async selectModel(input) {
1262
+ return super.selectModel(input);
1263
+ }
1264
+ };
1265
+ var GeminiRouter = class extends BaseRouter {
1266
+ constructor(config = {}) {
1267
+ super("gemini", config);
1268
+ }
1269
+ /**
1270
+ * Select optimal Gemini model
1271
+ *
1272
+ * @param input - User input and mode
1273
+ * @returns Selected model name (gemini-2.5-flash | gemini-2.5-pro)
1274
+ */
1275
+ async selectModel(input) {
1276
+ return super.selectModel(input);
1277
+ }
1278
+ };
1279
+
1280
+ // client.ts
1281
+ var MorphClient = class {
1282
+ /** Client configuration */
1283
+ config;
1284
+ /** FastApply tool for editing files with AI-powered merge */
1285
+ fastApply;
1286
+ /** CodebaseSearch tool for semantic code search */
1287
+ codebaseSearch;
1288
+ /** Browser tool for AI-powered browser automation */
1289
+ browser;
1290
+ /** Git tool for version control operations */
1291
+ git;
1292
+ /** Model routers for intelligent model selection */
1293
+ routers;
1294
+ /**
1295
+ * Create a new Morph SDK client
1296
+ *
1297
+ * @param config - Client configuration (apiKey, debug, timeout, retryConfig)
1298
+ *
1299
+ * @example
1300
+ * ```typescript
1301
+ * const morph = new MorphClient({
1302
+ * apiKey: process.env.MORPH_API_KEY,
1303
+ * debug: true,
1304
+ * timeout: 60000
1305
+ * });
1306
+ * ```
1307
+ */
1308
+ constructor(config = {}) {
1309
+ this.config = config;
1310
+ this.fastApply = new FastApplyClient({
1311
+ apiKey: config.apiKey,
1312
+ debug: config.debug,
1313
+ timeout: config.timeout,
1314
+ retryConfig: config.retryConfig
1315
+ });
1316
+ this.codebaseSearch = new CodebaseSearchClient({
1317
+ apiKey: config.apiKey,
1318
+ debug: config.debug,
1319
+ timeout: config.timeout,
1320
+ retryConfig: config.retryConfig
1321
+ });
1322
+ this.browser = new BrowserClient({
1323
+ apiKey: config.apiKey,
1324
+ debug: config.debug,
1325
+ timeout: config.timeout,
1326
+ retryConfig: config.retryConfig
1327
+ });
1328
+ this.git = new MorphGit({
1329
+ apiKey: config.apiKey,
1330
+ retryConfig: config.retryConfig
1331
+ });
1332
+ this.routers = {
1333
+ openai: new OpenAIRouter({
1334
+ apiKey: config.apiKey,
1335
+ debug: config.debug,
1336
+ timeout: config.timeout,
1337
+ retryConfig: config.retryConfig
1338
+ }),
1339
+ anthropic: new AnthropicRouter({
1340
+ apiKey: config.apiKey,
1341
+ debug: config.debug,
1342
+ timeout: config.timeout,
1343
+ retryConfig: config.retryConfig
1344
+ }),
1345
+ gemini: new GeminiRouter({
1346
+ apiKey: config.apiKey,
1347
+ debug: config.debug,
1348
+ timeout: config.timeout,
1349
+ retryConfig: config.retryConfig
1350
+ })
1351
+ };
1352
+ }
1353
+ };
1354
+ // Annotate the CommonJS export names for ESM import in node:
1355
+ 0 && (module.exports = {
1356
+ MorphClient
1357
+ });
1358
+ //# sourceMappingURL=client.cjs.map