@agentproto/adapter-mastra-agent 0.4.1 → 0.5.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.
@@ -1,602 +0,0 @@
1
- import { mkdirSync, promises } from 'fs';
2
- import { homedir, tmpdir } from 'os';
3
- import { join, resolve, isAbsolute, relative, sep } from 'path';
4
- import { LibSQLStore } from '@mastra/libsql';
5
- import { Memory } from '@mastra/memory';
6
- import { exec, execFile } from 'child_process';
7
- import { randomUUID } from 'crypto';
8
- import { promisify } from 'util';
9
- import { createTool } from '@mastra/core/tools';
10
- import { z } from 'zod';
11
- import { readFile } from 'fs/promises';
12
- import { parseAgentManifest, agentFromManifest } from '@agentproto/agent';
13
- import { buildMastraAgent } from '@agentproto/mastra';
14
- import { PROTOCOL_VERSION, ndJsonStream, AgentSideConnection } from '@agentclientprotocol/sdk';
15
- import { Writable, Readable } from 'stream';
16
-
17
- /**
18
- * @agentproto/adapter-mastra-agent v0.1.0-alpha
19
- * First-party agentproto agent: AGENT.md -> Mastra agent -> ACP server.
20
- */
21
-
22
- function resolveMemoryDbPath(env = process.env) {
23
- const override = env.AGENTPROTO_MASTRA_MEMORY_DB;
24
- if (override) return override;
25
- const dir = join(homedir(), ".agentproto", "mastra-agent");
26
- mkdirSync(dir, { recursive: true });
27
- return join(dir, "memory.db");
28
- }
29
- function buildSqliteMemory(config, env = process.env) {
30
- if (config?.scope === "none") return void 0;
31
- const dbPath = resolveMemoryDbPath(env);
32
- const lastMessages = typeof config?.retention_turns === "number" && config.retention_turns > 0 ? config.retention_turns : 20;
33
- return new Memory({
34
- storage: new LibSQLStore({ id: "mastra-agent-memory", url: `file:${dbPath}` }),
35
- options: {
36
- lastMessages,
37
- semanticRecall: false,
38
- workingMemory: { enabled: false }
39
- }
40
- });
41
- }
42
-
43
- // src/model-resolver.ts
44
- var PROVIDER_ENV = {
45
- openai: "OPENAI_API_KEY",
46
- anthropic: "ANTHROPIC_API_KEY",
47
- openrouter: "OPENROUTER_API_KEY",
48
- google: "GOOGLE_GENERATIVE_AI_API_KEY",
49
- groq: "GROQ_API_KEY",
50
- xai: "XAI_API_KEY",
51
- mistral: "MISTRAL_API_KEY",
52
- deepseek: "DEEPSEEK_API_KEY"
53
- };
54
- function modelRefToString(ref) {
55
- if (typeof ref === "string") return ref.trim();
56
- if (ref && typeof ref === "object" && typeof ref.ref === "string") {
57
- return ref.ref.trim();
58
- }
59
- throw new Error(
60
- "mastra-agent: AGENT.md `model` must be a `provider/model` string (or { ref }); inline model objects are not supported by this adapter."
61
- );
62
- }
63
- function providerOf(modelId) {
64
- const slash = modelId.indexOf("/");
65
- return slash > 0 ? modelId.slice(0, slash) : modelId;
66
- }
67
- function normalizeModelId(modelId) {
68
- if (modelId.includes("/")) return modelId;
69
- if (/^claude[-.]/i.test(modelId)) return `anthropic/${modelId}`;
70
- return modelId;
71
- }
72
- function resolveMastraModel(ref, env = process.env) {
73
- const modelId = normalizeModelId(modelRefToString(ref));
74
- if (!modelId) {
75
- throw new Error("mastra-agent: empty `model` ref.");
76
- }
77
- const provider = providerOf(modelId);
78
- const envKey = PROVIDER_ENV[provider];
79
- if (envKey && !env[envKey]) {
80
- throw new Error(
81
- `mastra-agent: model '${modelId}' needs ${envKey} in the environment (provider '${provider}'). Set it on the spawn env or export it.`
82
- );
83
- }
84
- return modelId;
85
- }
86
- var execAsync = promisify(exec);
87
- var execFileAsync = promisify(execFile);
88
- var ALLOWED_TEST_ARGV0 = /* @__PURE__ */ new Set(["npm", "pnpm", "yarn", "node", "npx"]);
89
- function tail(s, maxChars = 4e3) {
90
- return s.length > maxChars ? s.slice(-maxChars) : s;
91
- }
92
- function extractPatchPaths(patch) {
93
- const paths = /* @__PURE__ */ new Set();
94
- for (const line of patch.split("\n")) {
95
- const m = /^(?:\+\+\+|---) (?:a\/|b\/)?(.+?)(?:\t.*)?$/.exec(line);
96
- if (!m) continue;
97
- const p = m[1].trim();
98
- if (p === "/dev/null") continue;
99
- paths.add(p);
100
- }
101
- return [...paths];
102
- }
103
- function resolveInCwd(cwd, p) {
104
- const base = resolve(cwd);
105
- const target = isAbsolute(p) ? resolve(p) : resolve(base, p);
106
- const rel = relative(base, target);
107
- if (rel === "") return target;
108
- if (rel.startsWith("..") || isAbsolute(rel) && !target.startsWith(base + sep)) {
109
- throw new Error(
110
- `path '${p}' escapes the workspace (resolved to '${target}', outside '${base}').`
111
- );
112
- }
113
- return target;
114
- }
115
- function makeWorkspaceTools(opts) {
116
- const cwd = resolve(opts.cwd);
117
- const allowExec = opts.allowExec ?? true;
118
- const execTimeoutMs = opts.execTimeoutMs ?? 12e4;
119
- const execEnv = { ...process.env, GIT_CEILING_DIRECTORIES: resolve(cwd, "..") };
120
- const list_dir = createTool({
121
- id: "list_dir",
122
- description: "List the entries of a directory in the workspace. Returns names with a trailing '/' for directories. Path is relative to the workspace root (default '.').",
123
- inputSchema: z.object({
124
- path: z.string().default(".").describe("Directory path, relative to the workspace root.")
125
- }),
126
- outputSchema: z.object({ entries: z.array(z.string()) }),
127
- execute: async (input) => {
128
- const dir = resolveInCwd(cwd, input.path ?? ".");
129
- const dirents = await promises.readdir(dir, { withFileTypes: true });
130
- return {
131
- entries: dirents.map((d) => d.isDirectory() ? `${d.name}/` : d.name).sort()
132
- };
133
- }
134
- });
135
- const read_file = createTool({
136
- id: "read_file",
137
- description: "Read a UTF-8 text file from the workspace. Path is relative to the workspace root.",
138
- inputSchema: z.object({
139
- path: z.string().describe("File path, relative to the workspace root.")
140
- }),
141
- outputSchema: z.object({ content: z.string() }),
142
- execute: async (input) => {
143
- const file = resolveInCwd(cwd, input.path);
144
- return { content: await promises.readFile(file, "utf8") };
145
- }
146
- });
147
- const write_file = createTool({
148
- id: "write_file",
149
- description: "Write (creating or overwriting) a UTF-8 text file in the workspace. Creates parent directories as needed. Path is relative to the workspace root.",
150
- inputSchema: z.object({
151
- path: z.string().describe("File path, relative to the workspace root."),
152
- content: z.string().describe("Full file contents to write.")
153
- }),
154
- outputSchema: z.object({ path: z.string(), bytes: z.number() }),
155
- execute: async (input) => {
156
- const file = resolveInCwd(cwd, input.path);
157
- await promises.mkdir(resolve(file, ".."), { recursive: true });
158
- await promises.writeFile(file, input.content, "utf8");
159
- return { path: input.path, bytes: Buffer.byteLength(input.content, "utf8") };
160
- }
161
- });
162
- const edit_file = createTool({
163
- id: "edit_file",
164
- description: "Replace an exact substring in a workspace file. `old_string` must occur exactly once. Use for targeted edits instead of rewriting the whole file.",
165
- inputSchema: z.object({
166
- path: z.string().describe("File path, relative to the workspace root."),
167
- old_string: z.string().describe("Exact text to replace (must be unique in the file)."),
168
- new_string: z.string().describe("Replacement text.")
169
- }),
170
- outputSchema: z.object({ path: z.string(), replaced: z.boolean() }),
171
- execute: async (input) => {
172
- const file = resolveInCwd(cwd, input.path);
173
- const current = await promises.readFile(file, "utf8");
174
- const count = current.split(input.old_string).length - 1;
175
- if (count === 0) throw new Error(`old_string not found in '${input.path}'.`);
176
- if (count > 1) {
177
- throw new Error(`old_string occurs ${count}\xD7 in '${input.path}' \u2014 make it unique.`);
178
- }
179
- await promises.writeFile(file, current.replace(input.old_string, input.new_string), "utf8");
180
- return { path: input.path, replaced: true };
181
- }
182
- });
183
- const tools = {
184
- list_dir,
185
- read_file,
186
- write_file,
187
- edit_file
188
- };
189
- if (allowExec) {
190
- tools.run_command = createTool({
191
- id: "run_command",
192
- description: "Run a shell command in the workspace directory and return its stdout/stderr/exit code. Runs with a timeout; use for builds, tests, git, etc.",
193
- inputSchema: z.object({
194
- command: z.string().describe("The shell command to run (executed in the workspace root).")
195
- }),
196
- outputSchema: z.object({
197
- stdout: z.string(),
198
- stderr: z.string(),
199
- exitCode: z.number()
200
- }),
201
- execute: async (input) => {
202
- try {
203
- const { stdout, stderr } = await execAsync(input.command, {
204
- cwd,
205
- timeout: execTimeoutMs,
206
- maxBuffer: 10 * 1024 * 1024,
207
- env: execEnv
208
- });
209
- return { stdout, stderr, exitCode: 0 };
210
- } catch (err) {
211
- const e = err;
212
- return {
213
- stdout: e.stdout ?? "",
214
- stderr: e.stderr ?? e.message ?? String(err),
215
- exitCode: typeof e.code === "number" ? e.code : 1
216
- };
217
- }
218
- }
219
- });
220
- tools.read_diff = createTool({
221
- id: "read_diff",
222
- description: "Show `git diff` for the workspace \u2014 staged and unstaged changes against HEAD (or against `base` if given), as unified diff text. Optionally scoped to `paths`.",
223
- inputSchema: z.object({
224
- paths: z.array(z.string()).optional().describe("Restrict the diff to these paths, relative to the workspace root."),
225
- base: z.string().optional().describe("Git ref to diff against. Defaults to HEAD.")
226
- }),
227
- outputSchema: z.object({ diff: z.string() }),
228
- execute: async (input) => {
229
- const relPaths = (input.paths ?? []).map((p) => {
230
- const abs = resolveInCwd(cwd, p);
231
- return relative(cwd, abs) || ".";
232
- });
233
- const args = [
234
- "diff",
235
- input.base ?? "HEAD",
236
- ...relPaths.length ? ["--", ...relPaths] : []
237
- ];
238
- try {
239
- const { stdout } = await execFileAsync("git", args, {
240
- cwd,
241
- timeout: execTimeoutMs,
242
- maxBuffer: 10 * 1024 * 1024,
243
- env: execEnv
244
- });
245
- return { diff: stdout };
246
- } catch (err) {
247
- const e = err;
248
- throw new Error(`git diff failed: ${e.stderr ?? e.message ?? String(err)}`);
249
- }
250
- }
251
- });
252
- tools.apply_patch = createTool({
253
- id: "apply_patch",
254
- description: "Apply a unified diff to files in the workspace (`git apply --whitespace=nowarn`). Paths in the patch that escape the workspace are rejected.",
255
- inputSchema: z.object({
256
- patch: z.string().describe("Unified diff text to apply.")
257
- }),
258
- outputSchema: z.object({ applied: z.boolean(), output: z.string() }),
259
- execute: async (input) => {
260
- for (const p of extractPatchPaths(input.patch)) {
261
- resolveInCwd(cwd, p);
262
- }
263
- const patchFile = join(tmpdir(), `mastra-agent-patch-${randomUUID()}.diff`);
264
- await promises.writeFile(patchFile, input.patch, "utf8");
265
- try {
266
- const { stdout, stderr } = await execFileAsync(
267
- "git",
268
- ["apply", "--whitespace=nowarn", patchFile],
269
- { cwd, timeout: execTimeoutMs, maxBuffer: 10 * 1024 * 1024, env: execEnv }
270
- );
271
- return { applied: true, output: stdout || stderr || "" };
272
- } catch (err) {
273
- const e = err;
274
- throw new Error(`git apply failed: ${e.stderr ?? e.stdout ?? e.message ?? String(err)}`);
275
- } finally {
276
- await promises.unlink(patchFile).catch(() => {
277
- });
278
- }
279
- }
280
- });
281
- tools.run_tests = createTool({
282
- id: "run_tests",
283
- description: "Run the workspace's test command (default `npm test`, overridable via `command` or the MASTRA_AGENT_TEST_CMD env) and return its exit code + output tail.",
284
- inputSchema: z.object({
285
- command: z.string().optional().describe("Override the test command. Its argv0 must be one of npm, pnpm, yarn, node, npx.")
286
- }),
287
- outputSchema: z.object({ exitCode: z.number(), output: z.string() }),
288
- execute: async (input) => {
289
- const commandStr = input.command ?? process.env.MASTRA_AGENT_TEST_CMD ?? "npm test";
290
- const argv0 = commandStr.trim().split(/\s+/)[0];
291
- if (!argv0 || !ALLOWED_TEST_ARGV0.has(argv0)) {
292
- throw new Error(
293
- `run_tests: command '${commandStr}' is not allowed \u2014 argv0 must be one of ${[...ALLOWED_TEST_ARGV0].join(", ")}.`
294
- );
295
- }
296
- try {
297
- const { stdout, stderr } = await execAsync(commandStr, {
298
- cwd,
299
- timeout: execTimeoutMs,
300
- maxBuffer: 10 * 1024 * 1024,
301
- env: execEnv
302
- });
303
- return { exitCode: 0, output: tail(stdout + stderr) };
304
- } catch (err) {
305
- const e = err;
306
- return {
307
- exitCode: typeof e.code === "number" ? e.code : 1,
308
- output: tail((e.stdout ?? "") + (e.stderr ?? e.message ?? String(err)))
309
- };
310
- }
311
- }
312
- });
313
- }
314
- return {
315
- ...tools,
316
- ...opts.extraTools
317
- };
318
- }
319
- var DEFAULT_MODEL = "openrouter/z-ai/glm-5.2";
320
- var DEFAULT_TOOL_IDS = [
321
- "list_dir",
322
- "read_file",
323
- "write_file",
324
- "edit_file",
325
- "run_command"
326
- ];
327
- function defaultAgentManifest(model) {
328
- return [
329
- "---",
330
- "schema: agent/v1",
331
- "id: mastra-agent",
332
- "description: A first-party agentproto agent powered by Mastra.",
333
- `model: ${model}`,
334
- "version: 0.1.0",
335
- "tools:",
336
- ...DEFAULT_TOOL_IDS.map((id) => ` - ${id}`),
337
- "memory:",
338
- " scope: per-conversation",
339
- " retention_turns: 20",
340
- "---",
341
- "",
342
- "You are a capable, concise coding agent operating inside a workspace ",
343
- "directory. You can list, read, write, and edit files and run shell ",
344
- "commands there using your tools. Do exactly what the user asks \u2014 when ",
345
- "asked to reply with an exact string, reply with only that string.",
346
- ""
347
- ].join("\n");
348
- }
349
- function toolRefId(ref) {
350
- if (typeof ref === "string") return ref;
351
- if (ref && typeof ref === "object" && typeof ref.ref === "string") {
352
- return ref.ref;
353
- }
354
- return void 0;
355
- }
356
- async function resolveAgentSource(opts = {}) {
357
- if (opts.agentFile) return readFile(opts.agentFile, "utf8");
358
- return defaultAgentManifest(opts.model ?? DEFAULT_MODEL);
359
- }
360
- function makeAgentFactory(opts = {}) {
361
- return async () => {
362
- const source = await resolveAgentSource(opts);
363
- const { frontmatter, body } = parseAgentManifest(source);
364
- const handle = agentFromManifest({ frontmatter, body });
365
- const cwd = opts.cwd ?? process.cwd();
366
- const workspaceTools = makeWorkspaceTools({
367
- cwd,
368
- allowExec: opts.allowExec,
369
- extraTools: opts.extraTools
370
- });
371
- const { agent } = await buildMastraAgent(handle, {
372
- resolveModel: (ref) => resolveMastraModel(ref),
373
- // Match each declared tool ref against the workspace toolset by id.
374
- resolveTool: (ref) => {
375
- const id = toolRefId(ref);
376
- const tool = id ? workspaceTools[id] : void 0;
377
- return tool ? { name: id, tool } : void 0;
378
- },
379
- buildMemory: (config) => buildSqliteMemory(config),
380
- // The markdown body is the agent's primary system prompt (AIP-42).
381
- body
382
- });
383
- return agent;
384
- };
385
- }
386
-
387
- // src/tool-call-map.ts
388
- function toolKindFor(toolName) {
389
- switch (toolName) {
390
- case "read_file":
391
- case "list_dir":
392
- return "read";
393
- case "write_file":
394
- case "edit_file":
395
- return "edit";
396
- case "run_command":
397
- return "execute";
398
- default:
399
- return "other";
400
- }
401
- }
402
- function toolCallTitle(toolName, args) {
403
- if (args && typeof args === "object") {
404
- const { command, path, file } = args;
405
- const hint = typeof command === "string" && command || typeof path === "string" && path || typeof file === "string" && file || "";
406
- if (hint) return `${toolName}: ${hint}`;
407
- }
408
- return toolName;
409
- }
410
- function chunkToSessionUpdate(chunk) {
411
- switch (chunk.type) {
412
- case "text-delta": {
413
- const text = chunk.payload?.text;
414
- if (!text) return null;
415
- return {
416
- sessionUpdate: "agent_message_chunk",
417
- content: { type: "text", text }
418
- };
419
- }
420
- case "tool-call": {
421
- const toolCallId = chunk.payload?.toolCallId;
422
- if (!toolCallId) return null;
423
- const toolName = chunk.payload?.toolName ?? "tool";
424
- const args = chunk.payload?.args;
425
- return {
426
- sessionUpdate: "tool_call",
427
- toolCallId,
428
- title: toolCallTitle(toolName, args),
429
- kind: toolKindFor(toolName),
430
- status: "in_progress",
431
- rawInput: args
432
- };
433
- }
434
- case "tool-result": {
435
- const toolCallId = chunk.payload?.toolCallId;
436
- if (!toolCallId) return null;
437
- return {
438
- sessionUpdate: "tool_call_update",
439
- toolCallId,
440
- status: chunk.payload?.isError ? "failed" : "completed",
441
- rawOutput: chunk.payload?.result
442
- };
443
- }
444
- default:
445
- return null;
446
- }
447
- }
448
- function promptText(params) {
449
- const blocks = Array.isArray(params.prompt) ? params.prompt : [];
450
- return blocks.filter(
451
- (b) => Boolean(b) && b.type === "text" && typeof b.text === "string"
452
- ).map((b) => b.text).join("").trim();
453
- }
454
- var MastraAcpAgent = class {
455
- #conn;
456
- #buildAgent;
457
- #resource;
458
- #sessions = /* @__PURE__ */ new Map();
459
- #agent = null;
460
- constructor(conn, buildAgent, resource = "mastra-agent") {
461
- this.#conn = conn;
462
- this.#buildAgent = buildAgent;
463
- this.#resource = resource;
464
- }
465
- async initialize(_params) {
466
- return {
467
- protocolVersion: PROTOCOL_VERSION,
468
- agentCapabilities: {
469
- // Stateless per-prompt for now; no resume/replay surface.
470
- loadSession: false
471
- }
472
- };
473
- }
474
- async authenticate(_params) {
475
- return {};
476
- }
477
- async newSession(_params) {
478
- const sessionId = randomId();
479
- this.#sessions.set(sessionId, { prompt: null });
480
- return { sessionId };
481
- }
482
- async prompt(params) {
483
- const session = this.#sessions.get(params.sessionId);
484
- if (!session) throw new Error(`unknown session ${params.sessionId}`);
485
- session.prompt?.abort();
486
- const ac = new AbortController();
487
- session.prompt = ac;
488
- const text = promptText(params);
489
- try {
490
- const agent = await this.#ensureAgent();
491
- const result = await agent.stream(text, {
492
- abortSignal: ac.signal,
493
- memory: { thread: params.sessionId, resource: this.#resource },
494
- maxSteps: 200
495
- });
496
- if (result.fullStream) {
497
- await this.#pumpFullStream(params.sessionId, result.fullStream, ac);
498
- } else if (result.textStream) {
499
- await this.#pumpTextStream(params.sessionId, result.textStream, ac);
500
- }
501
- } catch (err) {
502
- if (ac.signal.aborted) return { stopReason: "cancelled" };
503
- await this.#conn.sessionUpdate({
504
- sessionId: params.sessionId,
505
- update: {
506
- sessionUpdate: "agent_message_chunk",
507
- content: {
508
- type: "text",
509
- text: `
510
- [mastra-agent error] ${err.message}
511
- `
512
- }
513
- }
514
- });
515
- session.prompt = null;
516
- return { stopReason: "refusal" };
517
- }
518
- const cancelled = ac.signal.aborted;
519
- session.prompt = null;
520
- return { stopReason: cancelled ? "cancelled" : "end_turn" };
521
- }
522
- async cancel(params) {
523
- this.#sessions.get(params.sessionId)?.prompt?.abort();
524
- }
525
- /**
526
- * The host applies the `model` (and other operator options) as a `--model`
527
- * spawn arg via the manifest `bin_args_template`, then ALSO calls this ACP
528
- * config hook (the daemon's default "config" apply path). The model is
529
- * already in effect, so this is a no-op that just reports our (empty) set of
530
- * runtime-configurable options. Without it the spawn fails with
531
- * "Method not found: session/set_config_option".
532
- */
533
- async setSessionConfigOption(_params) {
534
- return { configOptions: [] };
535
- }
536
- /** No agent-specific modes; accept and ignore so a host that sets one
537
- * doesn't error. */
538
- async setSessionMode(_params) {
539
- return {};
540
- }
541
- /** Drain Mastra's typed `fullStream`, mapping each chunk to an ACP
542
- * `session/update` (text deltas + tool_call / tool_call_update). */
543
- async #pumpFullStream(sessionId, stream, ac) {
544
- const reader = stream.getReader();
545
- try {
546
- for (; ; ) {
547
- const { value, done } = await reader.read();
548
- if (done || ac.signal.aborted) break;
549
- if (!value) continue;
550
- const update = chunkToSessionUpdate(value);
551
- if (update) await this.#conn.sessionUpdate({ sessionId, update });
552
- }
553
- } finally {
554
- reader.releaseLock();
555
- }
556
- }
557
- /** Fallback drain for an agent exposing only a plain text stream. */
558
- async #pumpTextStream(sessionId, stream, ac) {
559
- const reader = stream.getReader();
560
- try {
561
- for (; ; ) {
562
- const { value, done } = await reader.read();
563
- if (done || ac.signal.aborted) break;
564
- if (value) {
565
- await this.#conn.sessionUpdate({
566
- sessionId,
567
- update: {
568
- sessionUpdate: "agent_message_chunk",
569
- content: { type: "text", text: value }
570
- }
571
- });
572
- }
573
- }
574
- } finally {
575
- reader.releaseLock();
576
- }
577
- }
578
- async #ensureAgent() {
579
- if (!this.#agent) this.#agent = await this.#buildAgent();
580
- return this.#agent;
581
- }
582
- };
583
- function randomId() {
584
- const bytes = new Uint8Array(16);
585
- crypto.getRandomValues(bytes);
586
- return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
587
- }
588
- function runAcpOverStdio(buildAgent) {
589
- const toClient = Writable.toWeb(process.stdout);
590
- const fromClient = Readable.toWeb(
591
- process.stdin
592
- );
593
- const stream = ndJsonStream(toClient, fromClient);
594
- return new AgentSideConnection(
595
- (conn) => new MastraAcpAgent(conn, buildAgent),
596
- stream
597
- );
598
- }
599
-
600
- export { DEFAULT_MODEL, DEFAULT_TOOL_IDS, MastraAcpAgent, buildSqliteMemory, chunkToSessionUpdate, defaultAgentManifest, makeAgentFactory, makeWorkspaceTools, modelRefToString, promptText, providerOf, resolveInCwd, resolveMastraModel, resolveMemoryDbPath, runAcpOverStdio, toolCallTitle, toolKindFor };
601
- //# sourceMappingURL=chunk-ZVLJDGI4.mjs.map
602
- //# sourceMappingURL=chunk-ZVLJDGI4.mjs.map