@mastra/code-sdk 1.15.0-alpha.2 → 1.15.0-alpha.4
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.
- package/dist/acp/agent.d.ts.map +1 -1
- package/dist/acp/agent.js +1 -1
- package/dist/acp/agent.js.map +1 -1
- package/dist/acp/event-mapper.d.ts.map +1 -1
- package/dist/acp/event-mapper.js +1 -1
- package/dist/acp/event-mapper.js.map +1 -1
- package/dist/agent-connections/signal-provider.d.ts +1 -1
- package/dist/agent-connections/signal-provider.d.ts.map +1 -1
- package/dist/agent-connections/signal-provider.js.map +1 -1
- package/dist/agent-connections/state-processor.d.ts +2 -2
- package/dist/agent-connections/state-processor.d.ts.map +1 -1
- package/dist/agent-connections/state-processor.js.map +1 -1
- package/dist/agent-connections/thread-state.d.ts +1 -1
- package/dist/agent-connections/thread-state.d.ts.map +1 -1
- package/dist/agent-connections/thread-state.js.map +1 -1
- package/dist/agent-connections/tools.d.ts.map +1 -1
- package/dist/agent-connections/tools.js +1 -1
- package/dist/agent-connections/tools.js.map +1 -1
- package/dist/agents/credential-resolver.d.ts +6 -0
- package/dist/agents/credential-resolver.d.ts.map +1 -1
- package/dist/agents/credential-resolver.js +13 -4
- package/dist/agents/credential-resolver.js.map +1 -1
- package/dist/agents/sandbox-filesystem.d.ts.map +1 -1
- package/dist/agents/sandbox-filesystem.js +17 -6
- package/dist/agents/sandbox-filesystem.js.map +1 -1
- package/dist/experimental-agent.d.ts +1 -1
- package/dist/experimental-agent.d.ts.map +1 -1
- package/dist/experimental-agent.js.map +1 -1
- package/dist/factory/client.d.ts +41 -0
- package/dist/factory/client.d.ts.map +1 -0
- package/dist/factory/client.js +98 -0
- package/dist/factory/client.js.map +1 -0
- package/dist/factory/remote-controller.d.ts +34 -0
- package/dist/factory/remote-controller.d.ts.map +1 -0
- package/dist/factory/remote-controller.js +43 -0
- package/dist/factory/remote-controller.js.map +1 -0
- package/dist/factory/remote-session.d.ts +210 -0
- package/dist/factory/remote-session.d.ts.map +1 -0
- package/dist/factory/remote-session.js +416 -0
- package/dist/factory/remote-session.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +34 -15
- package/dist/index.js.map +1 -1
- package/dist/onboarding/pack-activation.d.ts +2 -11
- package/dist/onboarding/pack-activation.d.ts.map +1 -1
- package/dist/onboarding/pack-activation.js.map +1 -1
- package/dist/onboarding/settings.d.ts +18 -0
- package/dist/onboarding/settings.d.ts.map +1 -1
- package/dist/onboarding/settings.js +28 -3
- package/dist/onboarding/settings.js.map +1 -1
- package/dist/platform/index.d.ts +74 -0
- package/dist/platform/index.d.ts.map +1 -0
- package/dist/platform/index.js +200 -0
- package/dist/platform/index.js.map +1 -0
- package/dist/process-memory-diagnostics.d.ts +2 -1
- package/dist/process-memory-diagnostics.d.ts.map +1 -1
- package/dist/process-memory-diagnostics.js.map +1 -1
- package/dist/tools/web-search.d.ts +1 -1
- package/dist/tools/web-search.d.ts.map +1 -1
- package/dist/tools/web-search.js.map +1 -1
- package/dist/utils/local-observability.d.ts +19 -0
- package/dist/utils/local-observability.d.ts.map +1 -0
- package/dist/utils/local-observability.js +57 -0
- package/dist/utils/local-observability.js.map +1 -0
- package/dist/utils/notification-dispatch.d.ts +27 -12
- package/dist/utils/notification-dispatch.d.ts.map +1 -1
- package/dist/utils/notification-dispatch.js +46 -24
- package/dist/utils/notification-dispatch.js.map +1 -1
- package/dist/utils/signals-pubsub.d.ts +5 -3
- package/dist/utils/signals-pubsub.d.ts.map +1 -1
- package/dist/utils/signals-pubsub.js +8 -6
- package/dist/utils/signals-pubsub.js.map +1 -1
- package/dist/utils/wake-session.d.ts +44 -0
- package/dist/utils/wake-session.d.ts.map +1 -0
- package/dist/utils/wake-session.js +79 -0
- package/dist/utils/wake-session.js.map +1 -0
- package/package.json +18 -19
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { join } from "path";
|
|
2
|
+
import { execFile } from "child_process";
|
|
3
|
+
import { homedir } from "os";
|
|
4
|
+
import { chmod, mkdir, readFile, writeFile } from "fs/promises";
|
|
5
|
+
import { createServer } from "http";
|
|
6
|
+
//#region src/platform/index.ts
|
|
7
|
+
/**
|
|
8
|
+
* Mastra Platform client for Mastra Code.
|
|
9
|
+
*
|
|
10
|
+
* Shares `~/.mastra/credentials.json` with the `mastra` CLI so a single login
|
|
11
|
+
* works for both. Unlike the CLI flow, nothing here writes to stdout or reads
|
|
12
|
+
* stdin, so it is safe to drive from the TUI.
|
|
13
|
+
*/
|
|
14
|
+
const MASTRA_PLATFORM_API_URL = process.env.MASTRA_PLATFORM_API_URL || "https://platform.mastra.ai";
|
|
15
|
+
const CREDENTIALS_FILE = join(join(homedir(), ".mastra"), "credentials.json");
|
|
16
|
+
async function loadPlatformCredentials(filePath = CREDENTIALS_FILE) {
|
|
17
|
+
try {
|
|
18
|
+
return JSON.parse(await readFile(filePath, "utf-8"));
|
|
19
|
+
} catch {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
async function savePlatformCredentials(creds, filePath = CREDENTIALS_FILE) {
|
|
24
|
+
await mkdir(join(filePath, ".."), {
|
|
25
|
+
recursive: true,
|
|
26
|
+
mode: 448
|
|
27
|
+
});
|
|
28
|
+
await writeFile(filePath, JSON.stringify(creds, null, 2), { mode: 384 });
|
|
29
|
+
await chmod(filePath, 384).catch(() => {});
|
|
30
|
+
}
|
|
31
|
+
async function verifyToken(token, signal) {
|
|
32
|
+
try {
|
|
33
|
+
return (await fetch(`${MASTRA_PLATFORM_API_URL}/v1/auth/verify`, {
|
|
34
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
35
|
+
signal
|
|
36
|
+
})).ok;
|
|
37
|
+
} catch {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
async function refreshToken(creds, signal) {
|
|
42
|
+
if (!creds.refreshToken) return null;
|
|
43
|
+
try {
|
|
44
|
+
const res = await fetch(`${MASTRA_PLATFORM_API_URL}/v1/auth/refresh-token`, {
|
|
45
|
+
method: "POST",
|
|
46
|
+
headers: { "Content-Type": "application/json" },
|
|
47
|
+
body: JSON.stringify({ refreshToken: creds.refreshToken }),
|
|
48
|
+
signal
|
|
49
|
+
});
|
|
50
|
+
if (!res.ok) return null;
|
|
51
|
+
const data = await res.json();
|
|
52
|
+
creds.token = data.accessToken;
|
|
53
|
+
creds.refreshToken = data.refreshToken;
|
|
54
|
+
await savePlatformCredentials(creds);
|
|
55
|
+
return data.accessToken;
|
|
56
|
+
} catch {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Returns a valid session from env (`MASTRA_API_TOKEN` + `MASTRA_ORG_ID`) or
|
|
62
|
+
* stored credentials, refreshing the token if needed. Returns null when the
|
|
63
|
+
* user must log in.
|
|
64
|
+
*/
|
|
65
|
+
async function getPlatformSession(signal) {
|
|
66
|
+
const envToken = process.env.MASTRA_API_TOKEN;
|
|
67
|
+
const envOrg = process.env.MASTRA_ORG_ID;
|
|
68
|
+
if (envToken && envOrg) return {
|
|
69
|
+
token: envToken,
|
|
70
|
+
orgId: envOrg
|
|
71
|
+
};
|
|
72
|
+
const creds = await loadPlatformCredentials();
|
|
73
|
+
if (!creds) return null;
|
|
74
|
+
const orgId = envOrg ?? creds.currentOrgId ?? creds.organizationId;
|
|
75
|
+
if (await verifyToken(creds.token, signal)) return {
|
|
76
|
+
token: creds.token,
|
|
77
|
+
orgId
|
|
78
|
+
};
|
|
79
|
+
const refreshed = await refreshToken(creds, signal);
|
|
80
|
+
return refreshed ? {
|
|
81
|
+
token: refreshed,
|
|
82
|
+
orgId
|
|
83
|
+
} : null;
|
|
84
|
+
}
|
|
85
|
+
function openBrowser(url) {
|
|
86
|
+
const [cmd, args] = process.platform === "darwin" ? ["open", [url]] : process.platform === "win32" ? ["cmd", [
|
|
87
|
+
"/c",
|
|
88
|
+
"start",
|
|
89
|
+
"",
|
|
90
|
+
url
|
|
91
|
+
]] : ["xdg-open", [url]];
|
|
92
|
+
execFile(cmd, args, () => {});
|
|
93
|
+
}
|
|
94
|
+
const CALLBACK_HTML = (ok) => `<!doctype html><html><body style="background:#0d0d0d;color:#fff;font-family:system-ui;display:flex;align-items:center;justify-content:center;min-height:100vh"><div style="text-align:center"><h1>${ok ? "Logged in!" : "Login failed"}</h1><p>${ok ? "You can close this tab and return to Mastra Code." : "Close this tab and try again."}</p></div></body></html>`;
|
|
95
|
+
/** Browser-based Mastra Platform login using the same callback protocol as `mastra auth login`. */
|
|
96
|
+
async function loginToPlatform(options = {}) {
|
|
97
|
+
const { signal } = options;
|
|
98
|
+
signal?.throwIfAborted();
|
|
99
|
+
const server = createServer();
|
|
100
|
+
const state = Buffer.from(globalThis.crypto.getRandomValues(/* @__PURE__ */ new Uint8Array(16))).toString("hex");
|
|
101
|
+
const port = await new Promise((resolve, reject) => {
|
|
102
|
+
server.once("error", reject);
|
|
103
|
+
server.listen(0, "127.0.0.1", () => {
|
|
104
|
+
const addr = server.address();
|
|
105
|
+
if (typeof addr === "object" && addr) resolve(addr.port);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
const loginUrl = `${MASTRA_PLATFORM_API_URL}/v1/auth/login?product=cli&cli_port=${port}&state=${state}`;
|
|
109
|
+
options.onUrl?.(loginUrl);
|
|
110
|
+
(options.openUrl ?? openBrowser)(loginUrl);
|
|
111
|
+
const creds = await new Promise((resolve, reject) => {
|
|
112
|
+
let settled = false;
|
|
113
|
+
const finish = (cb) => {
|
|
114
|
+
if (settled) return;
|
|
115
|
+
settled = true;
|
|
116
|
+
clearTimeout(timeout);
|
|
117
|
+
signal?.removeEventListener("abort", onAbort);
|
|
118
|
+
server.close(cb);
|
|
119
|
+
server.closeAllConnections();
|
|
120
|
+
};
|
|
121
|
+
const onAbort = () => finish(() => reject(/* @__PURE__ */ new Error("Login cancelled")));
|
|
122
|
+
const timeout = setTimeout(() => finish(() => reject(/* @__PURE__ */ new Error("Login timed out"))), options.timeoutMs ?? 300 * 1e3);
|
|
123
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
124
|
+
server.on("request", (req, res) => {
|
|
125
|
+
const url = new URL(req.url ?? "/", `http://localhost:${port}`);
|
|
126
|
+
if (url.pathname !== "/callback") return void res.writeHead(404).end();
|
|
127
|
+
const token = url.searchParams.get("token");
|
|
128
|
+
const userParam = url.searchParams.get("user");
|
|
129
|
+
const orgId = url.searchParams.get("org");
|
|
130
|
+
if (url.searchParams.get("state") !== state || !token || !userParam || !orgId) {
|
|
131
|
+
res.writeHead(400, { "Content-Type": "text/html" }).end(CALLBACK_HTML(false));
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
let user;
|
|
135
|
+
try {
|
|
136
|
+
user = JSON.parse(decodeURIComponent(userParam));
|
|
137
|
+
} catch {
|
|
138
|
+
res.writeHead(400, { "Content-Type": "text/html" }).end(CALLBACK_HTML(false));
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const refresh = url.searchParams.get("refresh_token");
|
|
142
|
+
res.writeHead(200, {
|
|
143
|
+
"Content-Type": "text/html",
|
|
144
|
+
Connection: "close"
|
|
145
|
+
}).end(CALLBACK_HTML(true));
|
|
146
|
+
finish(() => resolve({
|
|
147
|
+
token,
|
|
148
|
+
...refresh ? { refreshToken: refresh } : {},
|
|
149
|
+
user,
|
|
150
|
+
organizationId: orgId
|
|
151
|
+
}));
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
await savePlatformCredentials(creds, options.credentialsPath);
|
|
155
|
+
return creds;
|
|
156
|
+
}
|
|
157
|
+
async function platformGet(session, path, signal) {
|
|
158
|
+
const res = await fetch(`${MASTRA_PLATFORM_API_URL}${path}`, {
|
|
159
|
+
headers: {
|
|
160
|
+
Authorization: `Bearer ${session.token}`,
|
|
161
|
+
"x-organization-id": session.orgId
|
|
162
|
+
},
|
|
163
|
+
signal
|
|
164
|
+
});
|
|
165
|
+
if (!res.ok) {
|
|
166
|
+
const body = await res.json().catch(() => ({}));
|
|
167
|
+
throw new Error(`Mastra Platform request failed (${res.status}): ${body.message ?? body.error ?? path}`);
|
|
168
|
+
}
|
|
169
|
+
return await res.json();
|
|
170
|
+
}
|
|
171
|
+
async function fetchPlatformOrgs(session, signal) {
|
|
172
|
+
const data = await platformGet(session, "/v1/auth/orgs", signal);
|
|
173
|
+
return data.organizations ?? data.orgs ?? [];
|
|
174
|
+
}
|
|
175
|
+
async function fetchPlatformProjects(session, signal) {
|
|
176
|
+
return (await platformGet(session, "/v1/projects", signal)).projects;
|
|
177
|
+
}
|
|
178
|
+
async function fetchPlatformEnvironments(session, projectId, signal) {
|
|
179
|
+
return (await platformGet(session, `/v1/projects/${encodeURIComponent(projectId)}/environments`, signal)).environments;
|
|
180
|
+
}
|
|
181
|
+
const FACTORY_DOMAIN = "factory.mastra.cloud";
|
|
182
|
+
/**
|
|
183
|
+
* The Factory server URL for a deployed environment: a custom server wins,
|
|
184
|
+
* otherwise the managed `<env slug>.factory.mastra.cloud` domain.
|
|
185
|
+
*/
|
|
186
|
+
function resolveFactoryUrl(env) {
|
|
187
|
+
if (env.customServerUrl) try {
|
|
188
|
+
const url = new URL(/^[a-z][a-z\d+.-]*:\/\//i.test(env.customServerUrl) ? env.customServerUrl : `https://${env.customServerUrl}`);
|
|
189
|
+
if (url.protocol !== "https:") return null;
|
|
190
|
+
return `${url.origin}${url.pathname}`.replace(/\/+$/, "");
|
|
191
|
+
} catch {
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
if (!env.instanceUrl) return null;
|
|
195
|
+
return `https://${env.slug}.${FACTORY_DOMAIN}`;
|
|
196
|
+
}
|
|
197
|
+
//#endregion
|
|
198
|
+
export { FACTORY_DOMAIN, MASTRA_PLATFORM_API_URL, fetchPlatformEnvironments, fetchPlatformOrgs, fetchPlatformProjects, getPlatformSession, loadPlatformCredentials, loginToPlatform, resolveFactoryUrl, savePlatformCredentials };
|
|
199
|
+
|
|
200
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/platform/index.ts"],"sourcesContent":["import { execFile } from 'node:child_process';\nimport { chmod, mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { createServer } from 'node:http';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\n/**\n * Mastra Platform client for Mastra Code.\n *\n * Shares `~/.mastra/credentials.json` with the `mastra` CLI so a single login\n * works for both. Unlike the CLI flow, nothing here writes to stdout or reads\n * stdin, so it is safe to drive from the TUI.\n */\n\nexport const MASTRA_PLATFORM_API_URL = process.env.MASTRA_PLATFORM_API_URL || 'https://platform.mastra.ai';\n\nconst CREDENTIALS_DIR = join(homedir(), '.mastra');\nconst CREDENTIALS_FILE = join(CREDENTIALS_DIR, 'credentials.json');\n\nexport interface PlatformCredentials {\n token: string;\n refreshToken?: string;\n user: { id: string; email: string; firstName: string | null; lastName: string | null };\n organizationId: string;\n currentOrgId?: string;\n}\n\nexport interface PlatformOrg {\n id: string;\n name: string;\n role?: string;\n isCurrent?: boolean;\n}\n\nexport interface PlatformProject {\n id: string;\n name: string;\n slug: string | null;\n organizationId: string;\n}\n\nexport interface PlatformEnvironment {\n id: string;\n projectId: string;\n name: string;\n slug: string;\n type: 'production' | 'staging' | 'preview';\n instanceUrl: string | null;\n customServerUrl: string | null;\n}\n\nexport interface PlatformSession {\n token: string;\n orgId: string;\n}\n\nexport async function loadPlatformCredentials(filePath = CREDENTIALS_FILE): Promise<PlatformCredentials | null> {\n try {\n return JSON.parse(await readFile(filePath, 'utf-8')) as PlatformCredentials;\n } catch {\n return null;\n }\n}\n\nexport async function savePlatformCredentials(creds: PlatformCredentials, filePath = CREDENTIALS_FILE): Promise<void> {\n const dir = join(filePath, '..');\n await mkdir(dir, { recursive: true, mode: 0o700 });\n await writeFile(filePath, JSON.stringify(creds, null, 2), { mode: 0o600 });\n await chmod(filePath, 0o600).catch(() => {});\n}\n\nasync function verifyToken(token: string, signal?: AbortSignal): Promise<boolean> {\n try {\n const res = await fetch(`${MASTRA_PLATFORM_API_URL}/v1/auth/verify`, {\n headers: { Authorization: `Bearer ${token}` },\n signal,\n });\n return res.ok;\n } catch {\n return false;\n }\n}\n\nasync function refreshToken(creds: PlatformCredentials, signal?: AbortSignal): Promise<string | null> {\n if (!creds.refreshToken) return null;\n try {\n const res = await fetch(`${MASTRA_PLATFORM_API_URL}/v1/auth/refresh-token`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ refreshToken: creds.refreshToken }),\n signal,\n });\n if (!res.ok) return null;\n const data = (await res.json()) as { accessToken: string; refreshToken: string };\n creds.token = data.accessToken;\n creds.refreshToken = data.refreshToken;\n await savePlatformCredentials(creds);\n return data.accessToken;\n } catch {\n return null;\n }\n}\n\n/**\n * Returns a valid session from env (`MASTRA_API_TOKEN` + `MASTRA_ORG_ID`) or\n * stored credentials, refreshing the token if needed. Returns null when the\n * user must log in.\n */\nexport async function getPlatformSession(signal?: AbortSignal): Promise<PlatformSession | null> {\n const envToken = process.env.MASTRA_API_TOKEN;\n const envOrg = process.env.MASTRA_ORG_ID;\n if (envToken && envOrg) return { token: envToken, orgId: envOrg };\n\n const creds = await loadPlatformCredentials();\n if (!creds) return null;\n const orgId = envOrg ?? creds.currentOrgId ?? creds.organizationId;\n if (await verifyToken(creds.token, signal)) return { token: creds.token, orgId };\n const refreshed = await refreshToken(creds, signal);\n return refreshed ? { token: refreshed, orgId } : null;\n}\n\nfunction openBrowser(url: string): void {\n const [cmd, args] =\n process.platform === 'darwin'\n ? ['open', [url]]\n : process.platform === 'win32'\n ? ['cmd', ['/c', 'start', '', url]]\n : ['xdg-open', [url]];\n execFile(cmd, args as string[], () => {});\n}\n\nexport interface PlatformLoginOptions {\n signal?: AbortSignal;\n timeoutMs?: number;\n /** Called with the login URL so the UI can display it in case the browser does not open. */\n onUrl?: (url: string) => void;\n /** Override for tests. */\n openUrl?: (url: string) => void;\n credentialsPath?: string;\n}\n\nconst CALLBACK_HTML = (ok: boolean) =>\n `<!doctype html><html><body style=\"background:#0d0d0d;color:#fff;font-family:system-ui;display:flex;align-items:center;justify-content:center;min-height:100vh\"><div style=\"text-align:center\"><h1>${\n ok ? 'Logged in!' : 'Login failed'\n }</h1><p>${ok ? 'You can close this tab and return to Mastra Code.' : 'Close this tab and try again.'}</p></div></body></html>`;\n\n/** Browser-based Mastra Platform login using the same callback protocol as `mastra auth login`. */\nexport async function loginToPlatform(options: PlatformLoginOptions = {}): Promise<PlatformCredentials> {\n const { signal } = options;\n signal?.throwIfAborted();\n\n const server = createServer();\n const state = Buffer.from(globalThis.crypto.getRandomValues(new Uint8Array(16))).toString('hex');\n const port = await new Promise<number>((resolve, reject) => {\n server.once('error', reject);\n server.listen(0, '127.0.0.1', () => {\n const addr = server.address();\n if (typeof addr === 'object' && addr) resolve(addr.port);\n });\n });\n\n const loginUrl = `${MASTRA_PLATFORM_API_URL}/v1/auth/login?product=cli&cli_port=${port}&state=${state}`;\n options.onUrl?.(loginUrl);\n (options.openUrl ?? openBrowser)(loginUrl);\n\n const creds = await new Promise<PlatformCredentials>((resolve, reject) => {\n let settled = false;\n const finish = (cb: () => void) => {\n if (settled) return;\n settled = true;\n clearTimeout(timeout);\n signal?.removeEventListener('abort', onAbort);\n server.close(cb);\n server.closeAllConnections();\n };\n const onAbort = () => finish(() => reject(new Error('Login cancelled')));\n const timeout = setTimeout(\n () => finish(() => reject(new Error('Login timed out'))),\n options.timeoutMs ?? 5 * 60 * 1000,\n );\n signal?.addEventListener('abort', onAbort, { once: true });\n\n server.on('request', (req, res) => {\n const url = new URL(req.url ?? '/', `http://localhost:${port}`);\n if (url.pathname !== '/callback') return void res.writeHead(404).end();\n\n const token = url.searchParams.get('token');\n const userParam = url.searchParams.get('user');\n const orgId = url.searchParams.get('org');\n if (url.searchParams.get('state') !== state || !token || !userParam || !orgId) {\n res.writeHead(400, { 'Content-Type': 'text/html' }).end(CALLBACK_HTML(false));\n return;\n }\n let user: PlatformCredentials['user'];\n try {\n user = JSON.parse(decodeURIComponent(userParam));\n } catch {\n res.writeHead(400, { 'Content-Type': 'text/html' }).end(CALLBACK_HTML(false));\n return;\n }\n const refresh = url.searchParams.get('refresh_token');\n res.writeHead(200, { 'Content-Type': 'text/html', Connection: 'close' }).end(CALLBACK_HTML(true));\n finish(() =>\n resolve({\n token,\n ...(refresh ? { refreshToken: refresh } : {}),\n user,\n organizationId: orgId,\n }),\n );\n });\n });\n\n await savePlatformCredentials(creds, options.credentialsPath);\n return creds;\n}\n\nasync function platformGet<T>(session: PlatformSession, path: string, signal?: AbortSignal): Promise<T> {\n const res = await fetch(`${MASTRA_PLATFORM_API_URL}${path}`, {\n headers: { Authorization: `Bearer ${session.token}`, 'x-organization-id': session.orgId },\n signal,\n });\n if (!res.ok) {\n const body = (await res.json().catch(() => ({}))) as { error?: string; message?: string };\n throw new Error(`Mastra Platform request failed (${res.status}): ${body.message ?? body.error ?? path}`);\n }\n return (await res.json()) as T;\n}\n\nexport async function fetchPlatformOrgs(session: PlatformSession, signal?: AbortSignal): Promise<PlatformOrg[]> {\n const data = await platformGet<{ organizations?: PlatformOrg[]; orgs?: PlatformOrg[] }>(\n session,\n '/v1/auth/orgs',\n signal,\n );\n return data.organizations ?? data.orgs ?? [];\n}\n\nexport async function fetchPlatformProjects(\n session: PlatformSession,\n signal?: AbortSignal,\n): Promise<PlatformProject[]> {\n return (await platformGet<{ projects: PlatformProject[] }>(session, '/v1/projects', signal)).projects;\n}\n\nexport async function fetchPlatformEnvironments(\n session: PlatformSession,\n projectId: string,\n signal?: AbortSignal,\n): Promise<PlatformEnvironment[]> {\n return (\n await platformGet<{ environments: PlatformEnvironment[] }>(\n session,\n `/v1/projects/${encodeURIComponent(projectId)}/environments`,\n signal,\n )\n ).environments;\n}\n\nexport const FACTORY_DOMAIN = 'factory.mastra.cloud';\n\n/**\n * The Factory server URL for a deployed environment: a custom server wins,\n * otherwise the managed `<env slug>.factory.mastra.cloud` domain.\n */\nexport function resolveFactoryUrl(env: PlatformEnvironment): string | null {\n if (env.customServerUrl) {\n // The Platform session token is sent to this URL, so only accept HTTPS.\n try {\n const url = new URL(\n /^[a-z][a-z\\d+.-]*:\\/\\//i.test(env.customServerUrl) ? env.customServerUrl : `https://${env.customServerUrl}`,\n );\n if (url.protocol !== 'https:') return null;\n return `${url.origin}${url.pathname}`.replace(/\\/+$/, '');\n } catch {\n return null;\n }\n }\n if (!env.instanceUrl) return null;\n return `https://${env.slug}.${FACTORY_DOMAIN}`;\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { PerformanceObserver
|
|
1
|
+
import { PerformanceObserver } from 'node:perf_hooks';
|
|
2
|
+
import type { PerformanceEntry } from 'node:perf_hooks';
|
|
2
3
|
import { getHeapSpaceStatistics, getHeapStatistics } from 'node:v8';
|
|
3
4
|
export declare const PROCESS_MEMORY_DIAGNOSTICS_DEFAULTS: {
|
|
4
5
|
readonly sampleIntervalMs: 10000;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"process-memory-diagnostics.d.ts","sourceRoot":"","sources":["../src/process-memory-diagnostics.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,mBAAmB,EAAE,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"process-memory-diagnostics.d.ts","sourceRoot":"","sources":["../src/process-memory-diagnostics.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"process-memory-diagnostics.js","names":["platform"],"sources":["../src/process-memory-diagnostics.ts"],"sourcesContent":["import { appendFile, chmod, mkdir, rename, rm, writeFile } from 'node:fs/promises';\nimport { Session } from 'node:inspector/promises';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { PerformanceObserver, type PerformanceEntry } from 'node:perf_hooks';\nimport { arch, platform } from 'node:process';\nimport { getHeapSpaceStatistics, getHeapStatistics } from 'node:v8';\n\nexport const PROCESS_MEMORY_DIAGNOSTICS_DEFAULTS = {\n sampleIntervalMs: 10_000,\n captureIntervalMs: 300_000,\n allocationIntervalBytes: 524_288,\n} as const;\n\nexport const PROCESS_MEMORY_DIAGNOSTICS_MINIMUMS = {\n sampleIntervalMs: 1_000,\n captureIntervalMs: 10_000,\n allocationIntervalBytes: 32_768,\n} as const;\n\nconst MAX_TIMER_DELAY_MS = 2_147_483_647;\nconst MAX_PENDING_GC_EVENTS = 1_000;\n\nexport interface ProcessMemoryDiagnosticsConfig {\n parentDirectory: string;\n sampleIntervalMs: number;\n captureIntervalMs: number;\n allocationIntervalBytes: number;\n}\n\nexport interface ProcessMemoryDiagnosticsEnvironment {\n MASTRACODE_PROFILE?: string;\n MASTRACODE_PROFILE_DIR?: string;\n MASTRACODE_PROFILE_SAMPLE_INTERVAL_MS?: string;\n MASTRACODE_PROFILE_CAPTURE_INTERVAL_MS?: string;\n MASTRACODE_PROFILE_ALLOCATION_INTERVAL_BYTES?: string;\n}\n\nexport interface ProcessMemoryDiagnosticsMemorySample {\n timestamp: string;\n sequence: number;\n elapsedMs: number;\n memory: ReturnType<typeof process.memoryUsage>;\n resourceUsage: ReturnType<typeof process.resourceUsage>;\n heap: ReturnType<typeof getHeapStatistics>;\n heapSpaces: ReturnType<typeof getHeapSpaceStatistics>;\n}\n\nexport interface ProcessMemoryDiagnosticsStatus {\n state: 'inactive' | 'starting' | 'active' | 'stopping' | 'error';\n outputDirectory: string | null;\n config: ProcessMemoryDiagnosticsConfig;\n sampleCount: number;\n captureCount: number;\n gcEventCount: number;\n latestSample: ProcessMemoryDiagnosticsMemorySample | null;\n latestCapturePath: string | null;\n error: string | null;\n}\n\nexport interface ProcessMemoryDiagnosticsCapture {\n path: string;\n sequence: number;\n timestamp: string;\n reason: 'manual' | 'periodic' | 'stop';\n}\n\ninterface InspectorSessionAdapter {\n connect(): void;\n disconnect(): void;\n post(method: string, params?: Record<string, unknown>): Promise<Record<string, unknown>>;\n}\n\ninterface PerformanceObserverAdapter {\n observe(options: Parameters<PerformanceObserver['observe']>[0]): void;\n disconnect(): void;\n}\n\ninterface ProcessMemoryDiagnosticsDependencies {\n createInspectorSession?: () => InspectorSessionAdapter;\n createPerformanceObserver?: (callback: (entries: PerformanceEntry[]) => void) => PerformanceObserverAdapter;\n now?: () => Date;\n randomId?: () => string;\n}\n\nexport interface ProcessMemoryDiagnosticsSetup {\n diagnostics: ProcessMemoryDiagnostics;\n enabled: boolean;\n error: string | null;\n}\n\nexport class ProcessMemoryDiagnosticsConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ProcessMemoryDiagnosticsConfigError';\n }\n}\n\nfunction isEnabled(value: string | undefined): boolean {\n return ['1', 'true', 'yes', 'on'].includes(value?.trim().toLowerCase() ?? '');\n}\n\nfunction parseBoundedInteger(\n env: ProcessMemoryDiagnosticsEnvironment,\n name: keyof ProcessMemoryDiagnosticsEnvironment,\n fallback: number,\n minimum: number,\n maximum?: number,\n): number {\n const raw = env[name];\n if (raw === undefined || raw.trim() === '') return fallback;\n const value = Number(raw);\n if (!Number.isSafeInteger(value) || value < minimum || (maximum !== undefined && value > maximum)) {\n const range = maximum === undefined ? `greater than or equal to ${minimum}` : `between ${minimum} and ${maximum}`;\n throw new ProcessMemoryDiagnosticsConfigError(\n `${name} must be an integer ${range}; received ${JSON.stringify(raw)}.`,\n );\n }\n return value;\n}\n\nfunction getDefaultProfileParentDirectory(): string {\n if (process.env.MASTRA_APP_DATA_DIR) return join(process.env.MASTRA_APP_DATA_DIR, 'profiles');\n\n const baseDirectory =\n platform === 'darwin'\n ? join(homedir(), 'Library', 'Application Support')\n : platform === 'win32'\n ? process.env.APPDATA || join(homedir(), 'AppData', 'Roaming')\n : process.env.XDG_DATA_HOME || join(homedir(), '.local', 'share');\n return join(baseDirectory, 'mastracode', 'profiles');\n}\n\nexport function parseProcessMemoryDiagnosticsEnvironment(env: ProcessMemoryDiagnosticsEnvironment = process.env): {\n enabled: boolean;\n config: ProcessMemoryDiagnosticsConfig;\n} {\n return {\n enabled: isEnabled(env.MASTRACODE_PROFILE),\n config: {\n parentDirectory: env.MASTRACODE_PROFILE_DIR?.trim() || getDefaultProfileParentDirectory(),\n sampleIntervalMs: parseBoundedInteger(\n env,\n 'MASTRACODE_PROFILE_SAMPLE_INTERVAL_MS',\n PROCESS_MEMORY_DIAGNOSTICS_DEFAULTS.sampleIntervalMs,\n PROCESS_MEMORY_DIAGNOSTICS_MINIMUMS.sampleIntervalMs,\n MAX_TIMER_DELAY_MS,\n ),\n captureIntervalMs: parseBoundedInteger(\n env,\n 'MASTRACODE_PROFILE_CAPTURE_INTERVAL_MS',\n PROCESS_MEMORY_DIAGNOSTICS_DEFAULTS.captureIntervalMs,\n PROCESS_MEMORY_DIAGNOSTICS_MINIMUMS.captureIntervalMs,\n MAX_TIMER_DELAY_MS,\n ),\n allocationIntervalBytes: parseBoundedInteger(\n env,\n 'MASTRACODE_PROFILE_ALLOCATION_INTERVAL_BYTES',\n PROCESS_MEMORY_DIAGNOSTICS_DEFAULTS.allocationIntervalBytes,\n PROCESS_MEMORY_DIAGNOSTICS_MINIMUMS.allocationIntervalBytes,\n ),\n },\n };\n}\n\nexport function createProcessMemoryDiagnosticsFromEnvironment(\n env: ProcessMemoryDiagnosticsEnvironment = process.env,\n dependencies: ProcessMemoryDiagnosticsDependencies = {},\n): ProcessMemoryDiagnosticsSetup {\n try {\n const { enabled, config } = parseProcessMemoryDiagnosticsEnvironment(env);\n return { diagnostics: new ProcessMemoryDiagnostics(config, dependencies), enabled, error: null };\n } catch (error) {\n const config: ProcessMemoryDiagnosticsConfig = {\n parentDirectory: env.MASTRACODE_PROFILE_DIR?.trim() || getDefaultProfileParentDirectory(),\n ...PROCESS_MEMORY_DIAGNOSTICS_DEFAULTS,\n };\n const message = error instanceof Error ? error.message : String(error);\n return {\n diagnostics: new ProcessMemoryDiagnostics(config, dependencies, message),\n enabled: isEnabled(env.MASTRACODE_PROFILE),\n error: message,\n };\n }\n}\n\nexport async function startConfiguredProcessMemoryDiagnostics(\n setup: ProcessMemoryDiagnosticsSetup,\n warn: (message: string) => void,\n): Promise<ProcessMemoryDiagnostics> {\n if (!setup.enabled) return setup.diagnostics;\n if (setup.error) {\n warn(`Process memory diagnostics were not started: ${setup.error}`);\n return setup.diagnostics;\n }\n\n const status = await setup.diagnostics.start();\n if (status.state !== 'active') {\n warn(`Process memory diagnostics were not started: ${status.error ?? 'unknown inspector error'}`);\n }\n return setup.diagnostics;\n}\n\nexport async function stopProcessMemoryDiagnosticsWithTimeout(\n diagnostics: ProcessMemoryDiagnostics,\n warn: (message: string) => void,\n timeoutMs = 5_000,\n): Promise<void> {\n let timeout: ReturnType<typeof setTimeout> | undefined;\n const timedOut = await Promise.race([\n diagnostics.stop().then(\n () => false,\n error => {\n warn(`Process memory diagnostics did not stop cleanly: ${errorMessage(error)}`);\n return false;\n },\n ),\n new Promise<true>(resolve => {\n timeout = setTimeout(() => resolve(true), timeoutMs);\n timeout.unref();\n }),\n ]);\n if (timeout) clearTimeout(timeout);\n if (timedOut)\n warn(`Process memory diagnostics did not stop within ${timeoutMs}ms; final artifacts may be incomplete.`);\n}\n\nfunction defaultInspectorSession(): InspectorSessionAdapter {\n const session = new Session();\n return {\n connect: () => session.connect(),\n disconnect: () => session.disconnect(),\n post: async (method, params) =>\n (await session.post(\n method as Parameters<Session['post']>[0],\n params as Parameters<Session['post']>[1],\n )) as unknown as Record<string, unknown>,\n };\n}\n\nfunction defaultPerformanceObserver(callback: (entries: PerformanceEntry[]) => void) {\n const observer = new PerformanceObserver(list => callback(list.getEntries()));\n return observer;\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction safeTimestamp(date: Date): string {\n return date.toISOString().replaceAll(':', '-');\n}\n\nfunction unrefTimer(timer: ReturnType<typeof setInterval>): void {\n timer.unref?.();\n}\n\nexport class ProcessMemoryDiagnostics {\n readonly config: ProcessMemoryDiagnosticsConfig;\n\n private state: ProcessMemoryDiagnosticsStatus['state'] = 'inactive';\n private outputDirectory: string | null = null;\n private inspector: InspectorSessionAdapter | null = null;\n private observer: PerformanceObserverAdapter | null = null;\n private sampleTimer: ReturnType<typeof setInterval> | null = null;\n private captureTimer: ReturnType<typeof setInterval> | null = null;\n private startedAt: Date | null = null;\n private sampleCount = 0;\n private captureCount = 0;\n private gcEventCount = 0;\n private latestSample: ProcessMemoryDiagnosticsMemorySample | null = null;\n private latestCapturePath: string | null = null;\n private latestError: string | null;\n private samplingActive = false;\n private stopRequested = false;\n private startingPromise: Promise<ProcessMemoryDiagnosticsStatus> | null = null;\n private stoppingPromise: Promise<ProcessMemoryDiagnosticsStatus> | null = null;\n private restartAfterStopPromise: Promise<ProcessMemoryDiagnosticsStatus> | null = null;\n private restartRequested = false;\n private pendingGcEvents: Array<Record<string, unknown>> = [];\n private gcEventBufferOverflowed = false;\n private artifactWriteFailed = false;\n private captureQueue: Promise<unknown> = Promise.resolve();\n private writeQueue: Promise<unknown> = Promise.resolve();\n\n private readonly configError: string | null;\n private readonly createInspectorSession: () => InspectorSessionAdapter;\n private readonly createPerformanceObserver: NonNullable<\n ProcessMemoryDiagnosticsDependencies['createPerformanceObserver']\n >;\n private readonly now: () => Date;\n private readonly randomId: () => string;\n\n constructor(\n config: ProcessMemoryDiagnosticsConfig,\n dependencies: ProcessMemoryDiagnosticsDependencies = {},\n initialError: string | null = null,\n ) {\n this.config = { ...config };\n this.configError = initialError;\n this.latestError = initialError;\n this.createInspectorSession = dependencies.createInspectorSession ?? defaultInspectorSession;\n this.createPerformanceObserver = dependencies.createPerformanceObserver ?? defaultPerformanceObserver;\n this.now = dependencies.now ?? (() => new Date());\n this.randomId = dependencies.randomId ?? (() => globalThis.crypto.randomUUID());\n }\n\n getStatus(): ProcessMemoryDiagnosticsStatus {\n return {\n state: this.state,\n outputDirectory: this.outputDirectory,\n config: { ...this.config },\n sampleCount: this.sampleCount,\n captureCount: this.captureCount,\n gcEventCount: this.gcEventCount,\n latestSample: this.latestSample,\n latestCapturePath: this.latestCapturePath,\n error: this.latestError,\n };\n }\n\n start(): Promise<ProcessMemoryDiagnosticsStatus> {\n if (this.state === 'active') return Promise.resolve(this.getStatus());\n if (this.state === 'starting' && this.startingPromise) return this.startingPromise;\n if (this.state === 'stopping' && this.stoppingPromise) {\n this.restartRequested = true;\n this.restartAfterStopPromise ??= this.stoppingPromise.then(() => {\n this.restartAfterStopPromise = null;\n if (!this.restartRequested) return this.getStatus();\n this.restartRequested = false;\n return this.start();\n });\n return this.restartAfterStopPromise;\n }\n if (this.configError) {\n this.latestError = this.configError;\n this.state = 'error';\n return Promise.resolve(this.getStatus());\n }\n\n this.state = 'starting';\n this.stoppingPromise = null;\n this.restartRequested = false;\n this.stopRequested = false;\n this.outputDirectory = null;\n this.sampleCount = 0;\n this.captureCount = 0;\n this.gcEventCount = 0;\n this.pendingGcEvents = [];\n this.gcEventBufferOverflowed = false;\n this.artifactWriteFailed = false;\n this.latestSample = null;\n this.latestCapturePath = null;\n this.latestError = null;\n this.startedAt = this.now();\n\n const startingPromise = this.startRun();\n this.startingPromise = startingPromise;\n void startingPromise.finally(() => {\n if (this.startingPromise === startingPromise) this.startingPromise = null;\n });\n return startingPromise;\n }\n\n private async startRun(): Promise<ProcessMemoryDiagnosticsStatus> {\n try {\n await this.createArtifacts();\n if (await this.abortStartIfRequested()) return this.getStatus();\n\n this.observeGc();\n this.inspector = this.createInspectorSession();\n this.inspector.connect();\n await this.startSampling();\n if (await this.abortStartIfRequested()) return this.getStatus();\n\n await this.takeSample();\n if (await this.abortStartIfRequested()) return this.getStatus();\n\n this.sampleTimer = setInterval(() => {\n void this.takeSample().catch(error => this.recordError('Process sample failed', error));\n }, this.config.sampleIntervalMs);\n unrefTimer(this.sampleTimer);\n\n this.captureTimer = setInterval(() => {\n void this.capture('periodic').catch(error => this.recordError('Periodic allocation capture failed', error));\n }, this.config.captureIntervalMs);\n unrefTimer(this.captureTimer);\n\n this.state = 'active';\n return this.getStatus();\n } catch (error) {\n this.latestError = `Unable to start process memory diagnostics: ${errorMessage(error)}`;\n await this.cleanupAfterStartFailure();\n this.state = 'error';\n return this.getStatus();\n }\n }\n\n private async abortStartIfRequested(): Promise<boolean> {\n if (!this.stopRequested) return false;\n await this.cleanupAfterStartFailure();\n this.state = 'inactive';\n return true;\n }\n\n capture(reason: 'manual' | 'periodic' = 'manual'): Promise<ProcessMemoryDiagnosticsCapture> {\n if (this.state !== 'active') {\n return Promise.reject(new Error(this.latestError ?? 'Process memory diagnostics are not active.'));\n }\n return this.enqueueCapture(() => this.captureEpoch(reason, false));\n }\n\n async stop(): Promise<ProcessMemoryDiagnosticsStatus> {\n if (this.stoppingPromise) {\n this.restartRequested = false;\n return this.stoppingPromise;\n }\n if (this.state === 'inactive') return this.getStatus();\n if (this.state === 'error' && !this.inspector && !this.outputDirectory) return this.getStatus();\n\n const startingPromise = this.state === 'starting' ? this.startingPromise : null;\n this.stopRequested = true;\n this.state = 'stopping';\n this.clearTimersAndObserver();\n\n if (startingPromise) {\n this.stoppingPromise = startingPromise.then(() => this.getStatus());\n return this.stoppingPromise;\n }\n\n this.stoppingPromise = (async () => {\n let stopError: string | null = null;\n try {\n if (this.outputDirectory) await this.takeSample();\n await this.enqueueCapture(async () => {\n if (this.inspector && this.samplingActive) await this.captureEpoch('stop', true);\n });\n await this.writeQueue;\n if (this.gcEventBufferOverflowed) {\n throw new Error(`GC event buffer exceeded ${MAX_PENDING_GC_EVENTS} records before the next process sample.`);\n }\n if (this.artifactWriteFailed) throw new Error('One or more process memory diagnostic artifact writes failed.');\n this.latestError = null;\n } catch (error) {\n stopError = `Unable to stop process memory diagnostics cleanly: ${errorMessage(error)}`;\n this.latestError = stopError;\n } finally {\n this.disconnectInspector();\n this.state = stopError ? 'error' : 'inactive';\n }\n return this.getStatus();\n })();\n\n return this.stoppingPromise;\n }\n\n private async createArtifacts(): Promise<void> {\n await mkdir(this.config.parentDirectory, { recursive: true, mode: 0o700 });\n await chmod(this.config.parentDirectory, 0o700);\n const runName = `run-${safeTimestamp(this.startedAt!)}-${process.pid}-${this.randomId()\n .replaceAll(/[^a-zA-Z0-9-]/g, '')\n .slice(0, 12)}`;\n this.outputDirectory = join(this.config.parentDirectory, runName);\n await mkdir(this.outputDirectory, { mode: 0o700 });\n await chmod(this.outputDirectory, 0o700);\n\n const metadata = {\n schemaVersion: 1,\n runId: runName,\n startedAt: this.startedAt!.toISOString(),\n pid: process.pid,\n nodeVersion: process.version,\n platform,\n arch,\n config: this.config,\n };\n await writeFile(join(this.outputDirectory, 'metadata.json'), `${JSON.stringify(metadata, null, 2)}\\n`, {\n flag: 'wx',\n mode: 0o600,\n });\n await writeFile(join(this.outputDirectory, 'process-samples.jsonl'), '', { flag: 'wx', mode: 0o600 });\n await writeFile(join(this.outputDirectory, 'gc-events.jsonl'), '', { flag: 'wx', mode: 0o600 });\n }\n\n private observeGc(): void {\n const observer = this.createPerformanceObserver(entries => {\n const before = this.latestSample?.memory ?? null;\n const after = process.memoryUsage();\n const timestamp = this.now().toISOString();\n for (const entry of entries) {\n const gcEntry = entry as PerformanceEntry & {\n kind?: number;\n flags?: number;\n detail?: { kind?: number; flags?: number };\n };\n this.gcEventCount += 1;\n if (this.pendingGcEvents.length >= MAX_PENDING_GC_EVENTS) {\n this.gcEventBufferOverflowed = true;\n this.latestError = `GC event buffer exceeded ${MAX_PENDING_GC_EVENTS} records before the next process sample.`;\n continue;\n }\n this.pendingGcEvents.push({\n timestamp,\n sequence: this.gcEventCount,\n name: entry.name,\n startTime: entry.startTime,\n duration: entry.duration,\n kind: gcEntry.detail?.kind ?? gcEntry.kind ?? null,\n flags: gcEntry.detail?.flags ?? gcEntry.flags ?? null,\n before,\n after,\n latestSampleSequence: this.latestSample?.sequence ?? null,\n });\n }\n });\n observer.observe({ entryTypes: ['gc'] });\n this.observer = observer;\n }\n\n private async startSampling(): Promise<void> {\n if (!this.inspector) throw new Error('Inspector session is unavailable.');\n await this.inspector.post('HeapProfiler.startSampling', {\n samplingInterval: this.config.allocationIntervalBytes,\n includeObjectsCollectedByMajorGC: true,\n includeObjectsCollectedByMinorGC: true,\n });\n this.samplingActive = true;\n }\n\n private async takeSample(): Promise<ProcessMemoryDiagnosticsMemorySample> {\n if (!this.outputDirectory || !this.startedAt) throw new Error('Diagnostics output directory is unavailable.');\n const sample: ProcessMemoryDiagnosticsMemorySample = {\n timestamp: this.now().toISOString(),\n sequence: this.sampleCount + 1,\n elapsedMs: Math.max(0, this.now().getTime() - this.startedAt.getTime()),\n memory: process.memoryUsage(),\n resourceUsage: process.resourceUsage(),\n heap: getHeapStatistics(),\n heapSpaces: getHeapSpaceStatistics(),\n };\n this.sampleCount = sample.sequence;\n this.latestSample = sample;\n await this.enqueueWrite('process-samples.jsonl', sample);\n const gcEvents = this.pendingGcEvents.splice(0);\n if (gcEvents.length > 0) await this.enqueueWriteBatch('gc-events.jsonl', gcEvents);\n return sample;\n }\n\n private enqueueWrite(fileName: string, value: unknown): Promise<void> {\n return this.enqueueWriteBatch(fileName, [value]);\n }\n\n private enqueueWriteBatch(fileName: string, values: unknown[]): Promise<void> {\n const operation = this.writeQueue.then(async () => {\n if (!this.outputDirectory || values.length === 0) return;\n const lines = values.map(value => JSON.stringify(value)).join('\\n');\n try {\n await appendFile(join(this.outputDirectory, fileName), `${lines}\\n`, { mode: 0o600 });\n } catch (error) {\n this.artifactWriteFailed = true;\n throw error;\n }\n });\n this.writeQueue = operation.catch(() => undefined);\n return operation;\n }\n\n private enqueueCapture<T>(operation: () => Promise<T>): Promise<T> {\n const result = this.captureQueue.then(operation);\n this.captureQueue = result.catch(() => undefined);\n return result;\n }\n\n private async captureEpoch(\n reason: ProcessMemoryDiagnosticsCapture['reason'],\n final: boolean,\n ): Promise<ProcessMemoryDiagnosticsCapture> {\n if (!this.inspector || !this.samplingActive || !this.outputDirectory) {\n throw new Error(this.latestError ?? 'Allocation sampling is not active.');\n }\n\n let response: Record<string, unknown>;\n try {\n response = await this.inspector.post('HeapProfiler.stopSampling');\n this.samplingActive = false;\n } catch (error) {\n this.latestError = `Allocation capture failed: ${errorMessage(error)}`;\n if (!final && !this.stopRequested) await this.restartSamplingAfterFailure();\n throw new Error(this.latestError, { cause: error });\n }\n\n const profile = response.profile;\n if (!profile || typeof profile !== 'object') {\n this.latestError = 'Allocation capture failed: inspector returned no profile.';\n if (!final && !this.stopRequested) await this.restartSamplingAfterFailure();\n throw new Error(this.latestError);\n }\n\n const sequence = this.captureCount + 1;\n const timestamp = this.now().toISOString();\n const filename = `allocation-${String(sequence).padStart(6, '0')}-${safeTimestamp(new Date(timestamp))}.heapprofile`;\n const finalPath = join(this.outputDirectory, filename);\n const temporaryPath = join(this.outputDirectory, `.${filename}.${this.randomId()}.tmp`);\n\n try {\n await writeFile(temporaryPath, `${JSON.stringify(profile)}\\n`, { flag: 'wx', mode: 0o600 });\n await chmod(temporaryPath, 0o600);\n await rename(temporaryPath, finalPath);\n await chmod(finalPath, 0o600);\n this.captureCount = sequence;\n this.latestCapturePath = finalPath;\n this.latestError = null;\n } catch (error) {\n this.artifactWriteFailed = true;\n this.latestError = `Unable to persist allocation capture: ${errorMessage(error)}`;\n throw new Error(this.latestError, { cause: error });\n } finally {\n if (!final && !this.stopRequested && this.state === 'active') {\n try {\n await this.startSampling();\n } catch (error) {\n this.latestError = `Unable to restart allocation sampling: ${errorMessage(error)}`;\n this.state = 'error';\n }\n }\n }\n\n if (!final && !this.stopRequested && !this.samplingActive) {\n throw new Error(this.latestError ?? 'Allocation sampling did not restart.');\n }\n\n return { path: finalPath, sequence, timestamp, reason };\n }\n\n private async restartSamplingAfterFailure(): Promise<void> {\n try {\n await this.startSampling();\n } catch (error) {\n this.latestError = `Unable to restart allocation sampling: ${errorMessage(error)}`;\n this.state = 'error';\n }\n }\n\n private recordError(prefix: string, error: unknown): void {\n this.latestError = `${prefix}: ${errorMessage(error)}`;\n }\n\n private clearTimersAndObserver(): void {\n if (this.sampleTimer) clearInterval(this.sampleTimer);\n if (this.captureTimer) clearInterval(this.captureTimer);\n this.sampleTimer = null;\n this.captureTimer = null;\n this.observer?.disconnect();\n this.observer = null;\n }\n\n private disconnectInspector(): void {\n this.samplingActive = false;\n if (!this.inspector) return;\n try {\n this.inspector.disconnect();\n } catch {\n // Best-effort cleanup after an inspector failure.\n }\n this.inspector = null;\n }\n\n private async cleanupAfterStartFailure(): Promise<void> {\n this.clearTimersAndObserver();\n this.disconnectInspector();\n await this.writeQueue;\n try {\n if (this.outputDirectory) await rm(this.outputDirectory, { recursive: true, force: true });\n } catch (error) {\n this.latestError = `${this.latestError} Failed to remove partial artifacts: ${errorMessage(error)}`;\n } finally {\n this.outputDirectory = null;\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"process-memory-diagnostics.js","names":["platform"],"sources":["../src/process-memory-diagnostics.ts"],"sourcesContent":["import { appendFile, chmod, mkdir, rename, rm, writeFile } from 'node:fs/promises';\nimport { Session } from 'node:inspector/promises';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { PerformanceObserver } from 'node:perf_hooks';\nimport type { PerformanceEntry } from 'node:perf_hooks';\nimport { arch, platform } from 'node:process';\nimport { getHeapSpaceStatistics, getHeapStatistics } from 'node:v8';\n\nexport const PROCESS_MEMORY_DIAGNOSTICS_DEFAULTS = {\n sampleIntervalMs: 10_000,\n captureIntervalMs: 300_000,\n allocationIntervalBytes: 524_288,\n} as const;\n\nexport const PROCESS_MEMORY_DIAGNOSTICS_MINIMUMS = {\n sampleIntervalMs: 1_000,\n captureIntervalMs: 10_000,\n allocationIntervalBytes: 32_768,\n} as const;\n\nconst MAX_TIMER_DELAY_MS = 2_147_483_647;\nconst MAX_PENDING_GC_EVENTS = 1_000;\n\nexport interface ProcessMemoryDiagnosticsConfig {\n parentDirectory: string;\n sampleIntervalMs: number;\n captureIntervalMs: number;\n allocationIntervalBytes: number;\n}\n\nexport interface ProcessMemoryDiagnosticsEnvironment {\n MASTRACODE_PROFILE?: string;\n MASTRACODE_PROFILE_DIR?: string;\n MASTRACODE_PROFILE_SAMPLE_INTERVAL_MS?: string;\n MASTRACODE_PROFILE_CAPTURE_INTERVAL_MS?: string;\n MASTRACODE_PROFILE_ALLOCATION_INTERVAL_BYTES?: string;\n}\n\nexport interface ProcessMemoryDiagnosticsMemorySample {\n timestamp: string;\n sequence: number;\n elapsedMs: number;\n memory: ReturnType<typeof process.memoryUsage>;\n resourceUsage: ReturnType<typeof process.resourceUsage>;\n heap: ReturnType<typeof getHeapStatistics>;\n heapSpaces: ReturnType<typeof getHeapSpaceStatistics>;\n}\n\nexport interface ProcessMemoryDiagnosticsStatus {\n state: 'inactive' | 'starting' | 'active' | 'stopping' | 'error';\n outputDirectory: string | null;\n config: ProcessMemoryDiagnosticsConfig;\n sampleCount: number;\n captureCount: number;\n gcEventCount: number;\n latestSample: ProcessMemoryDiagnosticsMemorySample | null;\n latestCapturePath: string | null;\n error: string | null;\n}\n\nexport interface ProcessMemoryDiagnosticsCapture {\n path: string;\n sequence: number;\n timestamp: string;\n reason: 'manual' | 'periodic' | 'stop';\n}\n\ninterface InspectorSessionAdapter {\n connect(): void;\n disconnect(): void;\n post(method: string, params?: Record<string, unknown>): Promise<Record<string, unknown>>;\n}\n\ninterface PerformanceObserverAdapter {\n observe(options: Parameters<PerformanceObserver['observe']>[0]): void;\n disconnect(): void;\n}\n\ninterface ProcessMemoryDiagnosticsDependencies {\n createInspectorSession?: () => InspectorSessionAdapter;\n createPerformanceObserver?: (callback: (entries: PerformanceEntry[]) => void) => PerformanceObserverAdapter;\n now?: () => Date;\n randomId?: () => string;\n}\n\nexport interface ProcessMemoryDiagnosticsSetup {\n diagnostics: ProcessMemoryDiagnostics;\n enabled: boolean;\n error: string | null;\n}\n\nexport class ProcessMemoryDiagnosticsConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ProcessMemoryDiagnosticsConfigError';\n }\n}\n\nfunction isEnabled(value: string | undefined): boolean {\n return ['1', 'true', 'yes', 'on'].includes(value?.trim().toLowerCase() ?? '');\n}\n\nfunction parseBoundedInteger(\n env: ProcessMemoryDiagnosticsEnvironment,\n name: keyof ProcessMemoryDiagnosticsEnvironment,\n fallback: number,\n minimum: number,\n maximum?: number,\n): number {\n const raw = env[name];\n if (raw === undefined || raw.trim() === '') return fallback;\n const value = Number(raw);\n if (!Number.isSafeInteger(value) || value < minimum || (maximum !== undefined && value > maximum)) {\n const range = maximum === undefined ? `greater than or equal to ${minimum}` : `between ${minimum} and ${maximum}`;\n throw new ProcessMemoryDiagnosticsConfigError(\n `${name} must be an integer ${range}; received ${JSON.stringify(raw)}.`,\n );\n }\n return value;\n}\n\nfunction getDefaultProfileParentDirectory(): string {\n if (process.env.MASTRA_APP_DATA_DIR) return join(process.env.MASTRA_APP_DATA_DIR, 'profiles');\n\n const baseDirectory =\n platform === 'darwin'\n ? join(homedir(), 'Library', 'Application Support')\n : platform === 'win32'\n ? process.env.APPDATA || join(homedir(), 'AppData', 'Roaming')\n : process.env.XDG_DATA_HOME || join(homedir(), '.local', 'share');\n return join(baseDirectory, 'mastracode', 'profiles');\n}\n\nexport function parseProcessMemoryDiagnosticsEnvironment(env: ProcessMemoryDiagnosticsEnvironment = process.env): {\n enabled: boolean;\n config: ProcessMemoryDiagnosticsConfig;\n} {\n return {\n enabled: isEnabled(env.MASTRACODE_PROFILE),\n config: {\n parentDirectory: env.MASTRACODE_PROFILE_DIR?.trim() || getDefaultProfileParentDirectory(),\n sampleIntervalMs: parseBoundedInteger(\n env,\n 'MASTRACODE_PROFILE_SAMPLE_INTERVAL_MS',\n PROCESS_MEMORY_DIAGNOSTICS_DEFAULTS.sampleIntervalMs,\n PROCESS_MEMORY_DIAGNOSTICS_MINIMUMS.sampleIntervalMs,\n MAX_TIMER_DELAY_MS,\n ),\n captureIntervalMs: parseBoundedInteger(\n env,\n 'MASTRACODE_PROFILE_CAPTURE_INTERVAL_MS',\n PROCESS_MEMORY_DIAGNOSTICS_DEFAULTS.captureIntervalMs,\n PROCESS_MEMORY_DIAGNOSTICS_MINIMUMS.captureIntervalMs,\n MAX_TIMER_DELAY_MS,\n ),\n allocationIntervalBytes: parseBoundedInteger(\n env,\n 'MASTRACODE_PROFILE_ALLOCATION_INTERVAL_BYTES',\n PROCESS_MEMORY_DIAGNOSTICS_DEFAULTS.allocationIntervalBytes,\n PROCESS_MEMORY_DIAGNOSTICS_MINIMUMS.allocationIntervalBytes,\n ),\n },\n };\n}\n\nexport function createProcessMemoryDiagnosticsFromEnvironment(\n env: ProcessMemoryDiagnosticsEnvironment = process.env,\n dependencies: ProcessMemoryDiagnosticsDependencies = {},\n): ProcessMemoryDiagnosticsSetup {\n try {\n const { enabled, config } = parseProcessMemoryDiagnosticsEnvironment(env);\n return { diagnostics: new ProcessMemoryDiagnostics(config, dependencies), enabled, error: null };\n } catch (error) {\n const config: ProcessMemoryDiagnosticsConfig = {\n parentDirectory: env.MASTRACODE_PROFILE_DIR?.trim() || getDefaultProfileParentDirectory(),\n ...PROCESS_MEMORY_DIAGNOSTICS_DEFAULTS,\n };\n const message = error instanceof Error ? error.message : String(error);\n return {\n diagnostics: new ProcessMemoryDiagnostics(config, dependencies, message),\n enabled: isEnabled(env.MASTRACODE_PROFILE),\n error: message,\n };\n }\n}\n\nexport async function startConfiguredProcessMemoryDiagnostics(\n setup: ProcessMemoryDiagnosticsSetup,\n warn: (message: string) => void,\n): Promise<ProcessMemoryDiagnostics> {\n if (!setup.enabled) return setup.diagnostics;\n if (setup.error) {\n warn(`Process memory diagnostics were not started: ${setup.error}`);\n return setup.diagnostics;\n }\n\n const status = await setup.diagnostics.start();\n if (status.state !== 'active') {\n warn(`Process memory diagnostics were not started: ${status.error ?? 'unknown inspector error'}`);\n }\n return setup.diagnostics;\n}\n\nexport async function stopProcessMemoryDiagnosticsWithTimeout(\n diagnostics: ProcessMemoryDiagnostics,\n warn: (message: string) => void,\n timeoutMs = 5_000,\n): Promise<void> {\n let timeout: ReturnType<typeof setTimeout> | undefined;\n const timedOut = await Promise.race([\n diagnostics.stop().then(\n () => false,\n error => {\n warn(`Process memory diagnostics did not stop cleanly: ${errorMessage(error)}`);\n return false;\n },\n ),\n new Promise<true>(resolve => {\n timeout = setTimeout(() => resolve(true), timeoutMs);\n timeout.unref();\n }),\n ]);\n if (timeout) clearTimeout(timeout);\n if (timedOut)\n warn(`Process memory diagnostics did not stop within ${timeoutMs}ms; final artifacts may be incomplete.`);\n}\n\nfunction defaultInspectorSession(): InspectorSessionAdapter {\n const session = new Session();\n return {\n connect: () => session.connect(),\n disconnect: () => session.disconnect(),\n post: async (method, params) =>\n (await session.post(\n method as Parameters<Session['post']>[0],\n params as Parameters<Session['post']>[1],\n )) as unknown as Record<string, unknown>,\n };\n}\n\nfunction defaultPerformanceObserver(callback: (entries: PerformanceEntry[]) => void) {\n const observer = new PerformanceObserver(list => callback(list.getEntries()));\n return observer;\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction safeTimestamp(date: Date): string {\n return date.toISOString().replaceAll(':', '-');\n}\n\nfunction unrefTimer(timer: ReturnType<typeof setInterval>): void {\n timer.unref?.();\n}\n\nexport class ProcessMemoryDiagnostics {\n readonly config: ProcessMemoryDiagnosticsConfig;\n\n private state: ProcessMemoryDiagnosticsStatus['state'] = 'inactive';\n private outputDirectory: string | null = null;\n private inspector: InspectorSessionAdapter | null = null;\n private observer: PerformanceObserverAdapter | null = null;\n private sampleTimer: ReturnType<typeof setInterval> | null = null;\n private captureTimer: ReturnType<typeof setInterval> | null = null;\n private startedAt: Date | null = null;\n private sampleCount = 0;\n private captureCount = 0;\n private gcEventCount = 0;\n private latestSample: ProcessMemoryDiagnosticsMemorySample | null = null;\n private latestCapturePath: string | null = null;\n private latestError: string | null;\n private samplingActive = false;\n private stopRequested = false;\n private startingPromise: Promise<ProcessMemoryDiagnosticsStatus> | null = null;\n private stoppingPromise: Promise<ProcessMemoryDiagnosticsStatus> | null = null;\n private restartAfterStopPromise: Promise<ProcessMemoryDiagnosticsStatus> | null = null;\n private restartRequested = false;\n private pendingGcEvents: Array<Record<string, unknown>> = [];\n private gcEventBufferOverflowed = false;\n private artifactWriteFailed = false;\n private captureQueue: Promise<unknown> = Promise.resolve();\n private writeQueue: Promise<unknown> = Promise.resolve();\n\n private readonly configError: string | null;\n private readonly createInspectorSession: () => InspectorSessionAdapter;\n private readonly createPerformanceObserver: NonNullable<\n ProcessMemoryDiagnosticsDependencies['createPerformanceObserver']\n >;\n private readonly now: () => Date;\n private readonly randomId: () => string;\n\n constructor(\n config: ProcessMemoryDiagnosticsConfig,\n dependencies: ProcessMemoryDiagnosticsDependencies = {},\n initialError: string | null = null,\n ) {\n this.config = { ...config };\n this.configError = initialError;\n this.latestError = initialError;\n this.createInspectorSession = dependencies.createInspectorSession ?? defaultInspectorSession;\n this.createPerformanceObserver = dependencies.createPerformanceObserver ?? defaultPerformanceObserver;\n this.now = dependencies.now ?? (() => new Date());\n this.randomId = dependencies.randomId ?? (() => globalThis.crypto.randomUUID());\n }\n\n getStatus(): ProcessMemoryDiagnosticsStatus {\n return {\n state: this.state,\n outputDirectory: this.outputDirectory,\n config: { ...this.config },\n sampleCount: this.sampleCount,\n captureCount: this.captureCount,\n gcEventCount: this.gcEventCount,\n latestSample: this.latestSample,\n latestCapturePath: this.latestCapturePath,\n error: this.latestError,\n };\n }\n\n start(): Promise<ProcessMemoryDiagnosticsStatus> {\n if (this.state === 'active') return Promise.resolve(this.getStatus());\n if (this.state === 'starting' && this.startingPromise) return this.startingPromise;\n if (this.state === 'stopping' && this.stoppingPromise) {\n this.restartRequested = true;\n this.restartAfterStopPromise ??= this.stoppingPromise.then(() => {\n this.restartAfterStopPromise = null;\n if (!this.restartRequested) return this.getStatus();\n this.restartRequested = false;\n return this.start();\n });\n return this.restartAfterStopPromise;\n }\n if (this.configError) {\n this.latestError = this.configError;\n this.state = 'error';\n return Promise.resolve(this.getStatus());\n }\n\n this.state = 'starting';\n this.stoppingPromise = null;\n this.restartRequested = false;\n this.stopRequested = false;\n this.outputDirectory = null;\n this.sampleCount = 0;\n this.captureCount = 0;\n this.gcEventCount = 0;\n this.pendingGcEvents = [];\n this.gcEventBufferOverflowed = false;\n this.artifactWriteFailed = false;\n this.latestSample = null;\n this.latestCapturePath = null;\n this.latestError = null;\n this.startedAt = this.now();\n\n const startingPromise = this.startRun();\n this.startingPromise = startingPromise;\n void startingPromise.finally(() => {\n if (this.startingPromise === startingPromise) this.startingPromise = null;\n });\n return startingPromise;\n }\n\n private async startRun(): Promise<ProcessMemoryDiagnosticsStatus> {\n try {\n await this.createArtifacts();\n if (await this.abortStartIfRequested()) return this.getStatus();\n\n this.observeGc();\n this.inspector = this.createInspectorSession();\n this.inspector.connect();\n await this.startSampling();\n if (await this.abortStartIfRequested()) return this.getStatus();\n\n await this.takeSample();\n if (await this.abortStartIfRequested()) return this.getStatus();\n\n this.sampleTimer = setInterval(() => {\n void this.takeSample().catch(error => this.recordError('Process sample failed', error));\n }, this.config.sampleIntervalMs);\n unrefTimer(this.sampleTimer);\n\n this.captureTimer = setInterval(() => {\n void this.capture('periodic').catch(error => this.recordError('Periodic allocation capture failed', error));\n }, this.config.captureIntervalMs);\n unrefTimer(this.captureTimer);\n\n this.state = 'active';\n return this.getStatus();\n } catch (error) {\n this.latestError = `Unable to start process memory diagnostics: ${errorMessage(error)}`;\n await this.cleanupAfterStartFailure();\n this.state = 'error';\n return this.getStatus();\n }\n }\n\n private async abortStartIfRequested(): Promise<boolean> {\n if (!this.stopRequested) return false;\n await this.cleanupAfterStartFailure();\n this.state = 'inactive';\n return true;\n }\n\n capture(reason: 'manual' | 'periodic' = 'manual'): Promise<ProcessMemoryDiagnosticsCapture> {\n if (this.state !== 'active') {\n return Promise.reject(new Error(this.latestError ?? 'Process memory diagnostics are not active.'));\n }\n return this.enqueueCapture(() => this.captureEpoch(reason, false));\n }\n\n async stop(): Promise<ProcessMemoryDiagnosticsStatus> {\n if (this.stoppingPromise) {\n this.restartRequested = false;\n return this.stoppingPromise;\n }\n if (this.state === 'inactive') return this.getStatus();\n if (this.state === 'error' && !this.inspector && !this.outputDirectory) return this.getStatus();\n\n const startingPromise = this.state === 'starting' ? this.startingPromise : null;\n this.stopRequested = true;\n this.state = 'stopping';\n this.clearTimersAndObserver();\n\n if (startingPromise) {\n this.stoppingPromise = startingPromise.then(() => this.getStatus());\n return this.stoppingPromise;\n }\n\n this.stoppingPromise = (async () => {\n let stopError: string | null = null;\n try {\n if (this.outputDirectory) await this.takeSample();\n await this.enqueueCapture(async () => {\n if (this.inspector && this.samplingActive) await this.captureEpoch('stop', true);\n });\n await this.writeQueue;\n if (this.gcEventBufferOverflowed) {\n throw new Error(`GC event buffer exceeded ${MAX_PENDING_GC_EVENTS} records before the next process sample.`);\n }\n if (this.artifactWriteFailed) throw new Error('One or more process memory diagnostic artifact writes failed.');\n this.latestError = null;\n } catch (error) {\n stopError = `Unable to stop process memory diagnostics cleanly: ${errorMessage(error)}`;\n this.latestError = stopError;\n } finally {\n this.disconnectInspector();\n this.state = stopError ? 'error' : 'inactive';\n }\n return this.getStatus();\n })();\n\n return this.stoppingPromise;\n }\n\n private async createArtifacts(): Promise<void> {\n await mkdir(this.config.parentDirectory, { recursive: true, mode: 0o700 });\n await chmod(this.config.parentDirectory, 0o700);\n const runName = `run-${safeTimestamp(this.startedAt!)}-${process.pid}-${this.randomId()\n .replaceAll(/[^a-zA-Z0-9-]/g, '')\n .slice(0, 12)}`;\n this.outputDirectory = join(this.config.parentDirectory, runName);\n await mkdir(this.outputDirectory, { mode: 0o700 });\n await chmod(this.outputDirectory, 0o700);\n\n const metadata = {\n schemaVersion: 1,\n runId: runName,\n startedAt: this.startedAt!.toISOString(),\n pid: process.pid,\n nodeVersion: process.version,\n platform,\n arch,\n config: this.config,\n };\n await writeFile(join(this.outputDirectory, 'metadata.json'), `${JSON.stringify(metadata, null, 2)}\\n`, {\n flag: 'wx',\n mode: 0o600,\n });\n await writeFile(join(this.outputDirectory, 'process-samples.jsonl'), '', { flag: 'wx', mode: 0o600 });\n await writeFile(join(this.outputDirectory, 'gc-events.jsonl'), '', { flag: 'wx', mode: 0o600 });\n }\n\n private observeGc(): void {\n const observer = this.createPerformanceObserver(entries => {\n const before = this.latestSample?.memory ?? null;\n const after = process.memoryUsage();\n const timestamp = this.now().toISOString();\n for (const entry of entries) {\n const gcEntry = entry as PerformanceEntry & {\n kind?: number;\n flags?: number;\n detail?: { kind?: number; flags?: number };\n };\n this.gcEventCount += 1;\n if (this.pendingGcEvents.length >= MAX_PENDING_GC_EVENTS) {\n this.gcEventBufferOverflowed = true;\n this.latestError = `GC event buffer exceeded ${MAX_PENDING_GC_EVENTS} records before the next process sample.`;\n continue;\n }\n this.pendingGcEvents.push({\n timestamp,\n sequence: this.gcEventCount,\n name: entry.name,\n startTime: entry.startTime,\n duration: entry.duration,\n kind: gcEntry.detail?.kind ?? gcEntry.kind ?? null,\n flags: gcEntry.detail?.flags ?? gcEntry.flags ?? null,\n before,\n after,\n latestSampleSequence: this.latestSample?.sequence ?? null,\n });\n }\n });\n observer.observe({ entryTypes: ['gc'] });\n this.observer = observer;\n }\n\n private async startSampling(): Promise<void> {\n if (!this.inspector) throw new Error('Inspector session is unavailable.');\n await this.inspector.post('HeapProfiler.startSampling', {\n samplingInterval: this.config.allocationIntervalBytes,\n includeObjectsCollectedByMajorGC: true,\n includeObjectsCollectedByMinorGC: true,\n });\n this.samplingActive = true;\n }\n\n private async takeSample(): Promise<ProcessMemoryDiagnosticsMemorySample> {\n if (!this.outputDirectory || !this.startedAt) throw new Error('Diagnostics output directory is unavailable.');\n const sample: ProcessMemoryDiagnosticsMemorySample = {\n timestamp: this.now().toISOString(),\n sequence: this.sampleCount + 1,\n elapsedMs: Math.max(0, this.now().getTime() - this.startedAt.getTime()),\n memory: process.memoryUsage(),\n resourceUsage: process.resourceUsage(),\n heap: getHeapStatistics(),\n heapSpaces: getHeapSpaceStatistics(),\n };\n this.sampleCount = sample.sequence;\n this.latestSample = sample;\n await this.enqueueWrite('process-samples.jsonl', sample);\n const gcEvents = this.pendingGcEvents.splice(0);\n if (gcEvents.length > 0) await this.enqueueWriteBatch('gc-events.jsonl', gcEvents);\n return sample;\n }\n\n private enqueueWrite(fileName: string, value: unknown): Promise<void> {\n return this.enqueueWriteBatch(fileName, [value]);\n }\n\n private enqueueWriteBatch(fileName: string, values: unknown[]): Promise<void> {\n const operation = this.writeQueue.then(async () => {\n if (!this.outputDirectory || values.length === 0) return;\n const lines = values.map(value => JSON.stringify(value)).join('\\n');\n try {\n await appendFile(join(this.outputDirectory, fileName), `${lines}\\n`, { mode: 0o600 });\n } catch (error) {\n this.artifactWriteFailed = true;\n throw error;\n }\n });\n this.writeQueue = operation.catch(() => undefined);\n return operation;\n }\n\n private enqueueCapture<T>(operation: () => Promise<T>): Promise<T> {\n const result = this.captureQueue.then(operation);\n this.captureQueue = result.catch(() => undefined);\n return result;\n }\n\n private async captureEpoch(\n reason: ProcessMemoryDiagnosticsCapture['reason'],\n final: boolean,\n ): Promise<ProcessMemoryDiagnosticsCapture> {\n if (!this.inspector || !this.samplingActive || !this.outputDirectory) {\n throw new Error(this.latestError ?? 'Allocation sampling is not active.');\n }\n\n let response: Record<string, unknown>;\n try {\n response = await this.inspector.post('HeapProfiler.stopSampling');\n this.samplingActive = false;\n } catch (error) {\n this.latestError = `Allocation capture failed: ${errorMessage(error)}`;\n if (!final && !this.stopRequested) await this.restartSamplingAfterFailure();\n throw new Error(this.latestError, { cause: error });\n }\n\n const profile = response.profile;\n if (!profile || typeof profile !== 'object') {\n this.latestError = 'Allocation capture failed: inspector returned no profile.';\n if (!final && !this.stopRequested) await this.restartSamplingAfterFailure();\n throw new Error(this.latestError);\n }\n\n const sequence = this.captureCount + 1;\n const timestamp = this.now().toISOString();\n const filename = `allocation-${String(sequence).padStart(6, '0')}-${safeTimestamp(new Date(timestamp))}.heapprofile`;\n const finalPath = join(this.outputDirectory, filename);\n const temporaryPath = join(this.outputDirectory, `.${filename}.${this.randomId()}.tmp`);\n\n try {\n await writeFile(temporaryPath, `${JSON.stringify(profile)}\\n`, { flag: 'wx', mode: 0o600 });\n await chmod(temporaryPath, 0o600);\n await rename(temporaryPath, finalPath);\n await chmod(finalPath, 0o600);\n this.captureCount = sequence;\n this.latestCapturePath = finalPath;\n this.latestError = null;\n } catch (error) {\n this.artifactWriteFailed = true;\n this.latestError = `Unable to persist allocation capture: ${errorMessage(error)}`;\n throw new Error(this.latestError, { cause: error });\n } finally {\n if (!final && !this.stopRequested && this.state === 'active') {\n try {\n await this.startSampling();\n } catch (error) {\n this.latestError = `Unable to restart allocation sampling: ${errorMessage(error)}`;\n this.state = 'error';\n }\n }\n }\n\n if (!final && !this.stopRequested && !this.samplingActive) {\n throw new Error(this.latestError ?? 'Allocation sampling did not restart.');\n }\n\n return { path: finalPath, sequence, timestamp, reason };\n }\n\n private async restartSamplingAfterFailure(): Promise<void> {\n try {\n await this.startSampling();\n } catch (error) {\n this.latestError = `Unable to restart allocation sampling: ${errorMessage(error)}`;\n this.state = 'error';\n }\n }\n\n private recordError(prefix: string, error: unknown): void {\n this.latestError = `${prefix}: ${errorMessage(error)}`;\n }\n\n private clearTimersAndObserver(): void {\n if (this.sampleTimer) clearInterval(this.sampleTimer);\n if (this.captureTimer) clearInterval(this.captureTimer);\n this.sampleTimer = null;\n this.captureTimer = null;\n this.observer?.disconnect();\n this.observer = null;\n }\n\n private disconnectInspector(): void {\n this.samplingActive = false;\n if (!this.inspector) return;\n try {\n this.inspector.disconnect();\n } catch {\n // Best-effort cleanup after an inspector failure.\n }\n this.inspector = null;\n }\n\n private async cleanupAfterStartFailure(): Promise<void> {\n this.clearTimersAndObserver();\n this.disconnectInspector();\n await this.writeQueue;\n try {\n if (this.outputDirectory) await rm(this.outputDirectory, { recursive: true, force: true });\n } catch (error) {\n this.latestError = `${this.latestError} Failed to remove partial artifacts: ${errorMessage(error)}`;\n } finally {\n this.outputDirectory = null;\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { WebSearchProviderSetting } from '../onboarding/settings.js';
|
|
2
2
|
/**
|
|
3
3
|
* Check whether a Tavily API key is available in the environment.
|
|
4
4
|
* Used to select model-independent web tools before falling back to
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web-search.d.ts","sourceRoot":"","sources":["../../src/tools/web-search.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"web-search.d.ts","sourceRoot":"","sources":["../../src/tools/web-search.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAwB1E;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAEtC;AAED,wEAAwE;AACxE,wBAAgB,cAAc,IAAI,OAAO,CAExC;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB;;;;;;;;;;;mIA8BlC;AAED;;;GAGG;AACH,wBAAgB,oBAAoB;;;;;;oIAwBnC;AAED;;;GAGG;AACH,wBAAgB,2BAA2B;;mIAuB1C;AAED;;;GAGG;AACH,wBAAgB,4BAA4B;;;;;;;;;qBAzIP,CAAC;sBAEnC,CAAC;4BACa,CAAC;;;oIA8JjB;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,UAAU,GAAE,wBAAiC,GAC5C,QAAQ,GAAG,UAAU,GAAG,SAAS,CAQnC;AAED;;;GAGG;AACH,wBAAgB,wBAAwB;;;;;;;;;;;;;yBAxLH,CAAC;0BAEnC,CAAC;gCACa,CAAC;;;;;;;;;;;;;;;;;;;;;;;;cAuMjB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web-search.js","names":[],"sources":["../../src/tools/web-search.ts"],"sourcesContent":["import { createTool, isValidationError, type ValidationError } from '@mastra/core/tools';\nimport { createParallelSearchTool, createParallelExtractTool } from '@mastra/parallel';\nimport { createTavilySearchTool, createTavilyExtractTool } from '@mastra/tavily';\nimport { z } from 'zod';\n\nimport { loadSettings, type WebSearchProviderSetting } from '../onboarding/settings.js';\nimport { truncateStringForTokenEstimate } from '../utils/token-estimator.js';\n\nconst MAX_WEB_SEARCH_TOKENS = 2_000;\nconst MAX_WEB_EXTRACT_TOKENS = 2_000;\n\nconst MIN_RELEVANCE_SCORE = 0.25;\n\nconst parallelWebSearchInputSchema = z.object({\n query: z.string().min(1).describe('The search query'),\n});\n\nfunction requireParallelOutput<T>(output: T | ValidationError | void, operation: 'search' | 'extract'): T {\n if (output === undefined) {\n throw new Error(`Parallel ${operation} returned no output`);\n }\n\n if (isValidationError(output)) {\n throw new Error(output.message);\n }\n\n return output;\n}\n\n/**\n * Check whether a Tavily API key is available in the environment.\n * Used to select model-independent web tools before falling back to\n * model-native web search.\n */\nexport function hasTavilyKey(): boolean {\n return !!process.env.TAVILY_API_KEY;\n}\n\n/** Check whether a Parallel API key is available in the environment. */\nexport function hasParallelKey(): boolean {\n return !!process.env.PARALLEL_API_KEY;\n}\n\n/**\n * Wraps the @mastra/tavily search tool with mastracode-specific behavior:\n * relevance filtering, markdown string formatting, and token truncation.\n * The underlying Tavily tool handles client init, input validation, and the API call.\n */\nexport function createWebSearchTool() {\n const tavilySearchTool = createTavilySearchTool();\n\n return createTool({\n id: 'web-search',\n description: tavilySearchTool.description!,\n inputSchema: tavilySearchTool.inputSchema!,\n execute: async (input, context) => {\n const output: any = await tavilySearchTool.execute!(input as any, context as any);\n\n const parts: string[] = [];\n\n if (output.answer) {\n parts.push(`Answer: ${output.answer}`);\n }\n\n const filtered = output.results.filter((r: any) => (r.score ?? 1) >= MIN_RELEVANCE_SCORE);\n for (const r of filtered) {\n parts.push(`## ${r.title}\\n${r.url}\\n${r.content}`);\n }\n\n const images = (output.images || []).map((img: any) => img.url).filter(Boolean);\n if (images.length > 0) {\n parts.push(`Images:\\n${images.join('\\n')}`);\n }\n\n const text = parts.join('\\n\\n');\n return truncateStringForTokenEstimate(text, MAX_WEB_SEARCH_TOKENS);\n },\n });\n}\n\n/**\n * Wraps the @mastra/tavily extract tool with mastracode-specific behavior:\n * markdown string formatting and token truncation.\n */\nexport function createWebExtractTool() {\n const tavilyExtractTool = createTavilyExtractTool();\n\n return createTool({\n id: 'web-extract',\n description: tavilyExtractTool.description!,\n inputSchema: tavilyExtractTool.inputSchema!,\n execute: async (input, context) => {\n const output: any = await tavilyExtractTool.execute!(input as any, context as any);\n\n const parts: string[] = [];\n\n for (const r of output.results) {\n parts.push(`## ${r.url}\\n${r.rawContent}`);\n }\n\n for (const r of output.failedResults) {\n parts.push(`## ${r.url}\\nError: ${r.error}`);\n }\n\n const text = parts.join('\\n\\n');\n return truncateStringForTokenEstimate(text, MAX_WEB_EXTRACT_TOKENS);\n },\n });\n}\n\n/**\n * Wraps the @mastra/parallel search tool with Mastra Code's standard tool id,\n * markdown string output, and token truncation.\n */\nexport function createParallelWebSearchTool() {\n const parallelSearchTool = createParallelSearchTool();\n\n return createTool({\n id: 'web-search',\n description: parallelSearchTool.description!,\n inputSchema: parallelWebSearchInputSchema,\n execute: async (input, context) => {\n const output = requireParallelOutput(\n await parallelSearchTool.execute!({ searchQueries: [input.query] }, context),\n 'search',\n );\n const parts: string[] = [];\n\n for (const result of output.results) {\n const title = result.title || result.url;\n const excerpts = (result.excerpts || []).filter(Boolean).join('\\n');\n parts.push([`## ${title}`, result.url, excerpts].filter(Boolean).join('\\n'));\n }\n\n return truncateStringForTokenEstimate(parts.join('\\n\\n'), MAX_WEB_SEARCH_TOKENS);\n },\n });\n}\n\n/**\n * Wraps the @mastra/parallel extract tool with Mastra Code's standard tool id,\n * markdown string output, and token truncation.\n */\nexport function createParallelWebExtractTool() {\n const parallelExtractTool = createParallelExtractTool();\n\n return createTool({\n id: 'web-extract',\n description: parallelExtractTool.description!,\n inputSchema: parallelExtractTool.inputSchema!,\n execute: async (input, context) => {\n const output = requireParallelOutput(await parallelExtractTool.execute!(input, context), 'extract');\n const parts: string[] = [];\n\n for (const result of output.results) {\n const content = result.fullContent || (result.excerpts || []).filter(Boolean).join('\\n');\n parts.push([`## ${result.url}`, content].filter(Boolean).join('\\n'));\n }\n\n for (const error of output.errors) {\n const status = error.httpStatusCode ? ` (${error.httpStatusCode})` : '';\n parts.push([`## ${error.url}`, `Error: ${error.errorType}${status}`, error.content].filter(Boolean).join('\\n'));\n }\n\n return truncateStringForTokenEstimate(parts.join('\\n\\n'), MAX_WEB_EXTRACT_TOKENS);\n },\n });\n}\n\n/**\n * Resolve which model-independent web provider to use. An explicit user\n * preference wins while its API key is configured; otherwise `auto` picks the\n * first configured provider key (Tavily, then Parallel).\n */\nexport function resolveWebSearchProvider(\n preference: WebSearchProviderSetting = 'auto',\n): 'tavily' | 'parallel' | undefined {\n if (preference === 'tavily' && hasTavilyKey()) return 'tavily';\n if (preference === 'parallel' && hasParallelKey()) return 'parallel';\n\n // `auto`, or an explicit choice whose key is no longer configured.\n if (hasTavilyKey()) return 'tavily';\n if (hasParallelKey()) return 'parallel';\n return undefined;\n}\n\n/**\n * Create the configured model-independent web tools for the provider selected\n * via the `webSearchProvider` preference (set in the TUI settings panel).\n */\nexport function createConfiguredWebTools() {\n const provider = resolveWebSearchProvider(loadSettings().preferences.webSearchProvider);\n\n if (provider === 'parallel') {\n return {\n web_search: createParallelWebSearchTool(),\n web_extract: createParallelWebExtractTool(),\n };\n }\n\n if (provider === 'tavily') {\n return {\n web_search: createWebSearchTool(),\n web_extract: createWebExtractTool(),\n };\n }\n\n return undefined;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"web-search.js","names":[],"sources":["../../src/tools/web-search.ts"],"sourcesContent":["import { createTool, isValidationError } from '@mastra/core/tools';\nimport type { ValidationError } from '@mastra/core/tools';\nimport { createParallelSearchTool, createParallelExtractTool } from '@mastra/parallel';\nimport { createTavilySearchTool, createTavilyExtractTool } from '@mastra/tavily';\nimport { z } from 'zod';\n\nimport { loadSettings } from '../onboarding/settings.js';\nimport type { WebSearchProviderSetting } from '../onboarding/settings.js';\nimport { truncateStringForTokenEstimate } from '../utils/token-estimator.js';\n\nconst MAX_WEB_SEARCH_TOKENS = 2_000;\nconst MAX_WEB_EXTRACT_TOKENS = 2_000;\n\nconst MIN_RELEVANCE_SCORE = 0.25;\n\nconst parallelWebSearchInputSchema = z.object({\n query: z.string().min(1).describe('The search query'),\n});\n\nfunction requireParallelOutput<T>(output: T | ValidationError | void, operation: 'search' | 'extract'): T {\n if (output === undefined) {\n throw new Error(`Parallel ${operation} returned no output`);\n }\n\n if (isValidationError(output)) {\n throw new Error(output.message);\n }\n\n return output;\n}\n\n/**\n * Check whether a Tavily API key is available in the environment.\n * Used to select model-independent web tools before falling back to\n * model-native web search.\n */\nexport function hasTavilyKey(): boolean {\n return !!process.env.TAVILY_API_KEY;\n}\n\n/** Check whether a Parallel API key is available in the environment. */\nexport function hasParallelKey(): boolean {\n return !!process.env.PARALLEL_API_KEY;\n}\n\n/**\n * Wraps the @mastra/tavily search tool with mastracode-specific behavior:\n * relevance filtering, markdown string formatting, and token truncation.\n * The underlying Tavily tool handles client init, input validation, and the API call.\n */\nexport function createWebSearchTool() {\n const tavilySearchTool = createTavilySearchTool();\n\n return createTool({\n id: 'web-search',\n description: tavilySearchTool.description!,\n inputSchema: tavilySearchTool.inputSchema!,\n execute: async (input, context) => {\n const output: any = await tavilySearchTool.execute!(input as any, context as any);\n\n const parts: string[] = [];\n\n if (output.answer) {\n parts.push(`Answer: ${output.answer}`);\n }\n\n const filtered = output.results.filter((r: any) => (r.score ?? 1) >= MIN_RELEVANCE_SCORE);\n for (const r of filtered) {\n parts.push(`## ${r.title}\\n${r.url}\\n${r.content}`);\n }\n\n const images = (output.images || []).map((img: any) => img.url).filter(Boolean);\n if (images.length > 0) {\n parts.push(`Images:\\n${images.join('\\n')}`);\n }\n\n const text = parts.join('\\n\\n');\n return truncateStringForTokenEstimate(text, MAX_WEB_SEARCH_TOKENS);\n },\n });\n}\n\n/**\n * Wraps the @mastra/tavily extract tool with mastracode-specific behavior:\n * markdown string formatting and token truncation.\n */\nexport function createWebExtractTool() {\n const tavilyExtractTool = createTavilyExtractTool();\n\n return createTool({\n id: 'web-extract',\n description: tavilyExtractTool.description!,\n inputSchema: tavilyExtractTool.inputSchema!,\n execute: async (input, context) => {\n const output: any = await tavilyExtractTool.execute!(input as any, context as any);\n\n const parts: string[] = [];\n\n for (const r of output.results) {\n parts.push(`## ${r.url}\\n${r.rawContent}`);\n }\n\n for (const r of output.failedResults) {\n parts.push(`## ${r.url}\\nError: ${r.error}`);\n }\n\n const text = parts.join('\\n\\n');\n return truncateStringForTokenEstimate(text, MAX_WEB_EXTRACT_TOKENS);\n },\n });\n}\n\n/**\n * Wraps the @mastra/parallel search tool with Mastra Code's standard tool id,\n * markdown string output, and token truncation.\n */\nexport function createParallelWebSearchTool() {\n const parallelSearchTool = createParallelSearchTool();\n\n return createTool({\n id: 'web-search',\n description: parallelSearchTool.description!,\n inputSchema: parallelWebSearchInputSchema,\n execute: async (input, context) => {\n const output = requireParallelOutput(\n await parallelSearchTool.execute!({ searchQueries: [input.query] }, context),\n 'search',\n );\n const parts: string[] = [];\n\n for (const result of output.results) {\n const title = result.title || result.url;\n const excerpts = (result.excerpts || []).filter(Boolean).join('\\n');\n parts.push([`## ${title}`, result.url, excerpts].filter(Boolean).join('\\n'));\n }\n\n return truncateStringForTokenEstimate(parts.join('\\n\\n'), MAX_WEB_SEARCH_TOKENS);\n },\n });\n}\n\n/**\n * Wraps the @mastra/parallel extract tool with Mastra Code's standard tool id,\n * markdown string output, and token truncation.\n */\nexport function createParallelWebExtractTool() {\n const parallelExtractTool = createParallelExtractTool();\n\n return createTool({\n id: 'web-extract',\n description: parallelExtractTool.description!,\n inputSchema: parallelExtractTool.inputSchema!,\n execute: async (input, context) => {\n const output = requireParallelOutput(await parallelExtractTool.execute!(input, context), 'extract');\n const parts: string[] = [];\n\n for (const result of output.results) {\n const content = result.fullContent || (result.excerpts || []).filter(Boolean).join('\\n');\n parts.push([`## ${result.url}`, content].filter(Boolean).join('\\n'));\n }\n\n for (const error of output.errors) {\n const status = error.httpStatusCode ? ` (${error.httpStatusCode})` : '';\n parts.push([`## ${error.url}`, `Error: ${error.errorType}${status}`, error.content].filter(Boolean).join('\\n'));\n }\n\n return truncateStringForTokenEstimate(parts.join('\\n\\n'), MAX_WEB_EXTRACT_TOKENS);\n },\n });\n}\n\n/**\n * Resolve which model-independent web provider to use. An explicit user\n * preference wins while its API key is configured; otherwise `auto` picks the\n * first configured provider key (Tavily, then Parallel).\n */\nexport function resolveWebSearchProvider(\n preference: WebSearchProviderSetting = 'auto',\n): 'tavily' | 'parallel' | undefined {\n if (preference === 'tavily' && hasTavilyKey()) return 'tavily';\n if (preference === 'parallel' && hasParallelKey()) return 'parallel';\n\n // `auto`, or an explicit choice whose key is no longer configured.\n if (hasTavilyKey()) return 'tavily';\n if (hasParallelKey()) return 'parallel';\n return undefined;\n}\n\n/**\n * Create the configured model-independent web tools for the provider selected\n * via the `webSearchProvider` preference (set in the TUI settings panel).\n */\nexport function createConfiguredWebTools() {\n const provider = resolveWebSearchProvider(loadSettings().preferences.webSearchProvider);\n\n if (provider === 'parallel') {\n return {\n web_search: createParallelWebSearchTool(),\n web_extract: createParallelWebExtractTool(),\n };\n }\n\n if (provider === 'tavily') {\n return {\n web_search: createWebSearchTool(),\n web_extract: createWebExtractTool(),\n };\n }\n\n return undefined;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { PruneResult, RetentionConfig } from '@mastra/core/storage';
|
|
2
|
+
import { DuckDBStore } from '@mastra/duckdb';
|
|
3
|
+
/**
|
|
4
|
+
* Age limits for the local trace store: 14 days for spans, metrics and logs,
|
|
5
|
+
* 30 days for scores and feedback. Spans, logs and scores use the same windows
|
|
6
|
+
* as libsql's `DEFAULT_RETENTION`, which has no metrics or feedback entries.
|
|
7
|
+
*/
|
|
8
|
+
export declare const LOCAL_OBSERVABILITY_RETENTION: RetentionConfig;
|
|
9
|
+
/**
|
|
10
|
+
* Open the local observability DuckDB file used when `/observability local on`.
|
|
11
|
+
* Connects eagerly so a lock error surfaces now, not mid-session, then prunes
|
|
12
|
+
* aged events in the background so the file cannot grow without bound.
|
|
13
|
+
* `pruned` never rejects; anything left over is pruned on the next open.
|
|
14
|
+
*/
|
|
15
|
+
export declare function openLocalObservabilityStore(path: string): Promise<{
|
|
16
|
+
store: DuckDBStore;
|
|
17
|
+
pruned: Promise<PruneResult[]>;
|
|
18
|
+
}>;
|
|
19
|
+
//# sourceMappingURL=local-observability.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-observability.d.ts","sourceRoot":"","sources":["../../src/utils/local-observability.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,EAAE,eAQ3C,CAAC;AAqBF;;;;;GAKG;AACH,wBAAsB,2BAA2B,CAC/C,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC,CAAA;CAAE,CAAC,CAMjE"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { DuckDBStore } from "@mastra/duckdb";
|
|
2
|
+
//#region src/utils/local-observability.ts
|
|
3
|
+
/**
|
|
4
|
+
* Age limits for the local trace store: 14 days for spans, metrics and logs,
|
|
5
|
+
* 30 days for scores and feedback. Spans, logs and scores use the same windows
|
|
6
|
+
* as libsql's `DEFAULT_RETENTION`, which has no metrics or feedback entries.
|
|
7
|
+
*/
|
|
8
|
+
const LOCAL_OBSERVABILITY_RETENTION = { observability: {
|
|
9
|
+
spans: { maxAge: "14d" },
|
|
10
|
+
metrics: { maxAge: "14d" },
|
|
11
|
+
logs: { maxAge: "14d" },
|
|
12
|
+
scores: { maxAge: "30d" },
|
|
13
|
+
feedback: { maxAge: "30d" }
|
|
14
|
+
} };
|
|
15
|
+
/** Upper bound on rows deleted per table per session, so startup pruning never runs long. */
|
|
16
|
+
const MAX_ROWS_PER_OPEN = 5e4;
|
|
17
|
+
const OBSERVABILITY_TABLES = [
|
|
18
|
+
"span_events",
|
|
19
|
+
"metric_events",
|
|
20
|
+
"log_events",
|
|
21
|
+
"score_events",
|
|
22
|
+
"feedback_events"
|
|
23
|
+
];
|
|
24
|
+
/**
|
|
25
|
+
* Prune only when every observability table already exists. A brand-new file
|
|
26
|
+
* has no tables until the session composite runs init(), and pruning it would
|
|
27
|
+
* log a missing-table error from the storage layer for a file with nothing to delete.
|
|
28
|
+
*/
|
|
29
|
+
async function pruneExistingTables(store) {
|
|
30
|
+
if ((await store.db.query(`SELECT table_name FROM information_schema.tables WHERE table_name IN (${OBSERVABILITY_TABLES.map(() => "?").join(", ")})`, OBSERVABILITY_TABLES)).length < OBSERVABILITY_TABLES.length) return [];
|
|
31
|
+
return store.prune({
|
|
32
|
+
maxRows: MAX_ROWS_PER_OPEN,
|
|
33
|
+
pauseMs: 10
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Open the local observability DuckDB file used when `/observability local on`.
|
|
38
|
+
* Connects eagerly so a lock error surfaces now, not mid-session, then prunes
|
|
39
|
+
* aged events in the background so the file cannot grow without bound.
|
|
40
|
+
* `pruned` never rejects; anything left over is pruned on the next open.
|
|
41
|
+
*/
|
|
42
|
+
async function openLocalObservabilityStore(path) {
|
|
43
|
+
const store = new DuckDBStore({
|
|
44
|
+
id: "mastra-code-observability",
|
|
45
|
+
path,
|
|
46
|
+
retention: LOCAL_OBSERVABILITY_RETENTION
|
|
47
|
+
});
|
|
48
|
+
await store.db.getConnection();
|
|
49
|
+
return {
|
|
50
|
+
store,
|
|
51
|
+
pruned: pruneExistingTables(store).catch(() => [])
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
export { LOCAL_OBSERVABILITY_RETENTION, openLocalObservabilityStore };
|
|
56
|
+
|
|
57
|
+
//# sourceMappingURL=local-observability.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-observability.js","names":[],"sources":["../../src/utils/local-observability.ts"],"sourcesContent":["import type { PruneResult, RetentionConfig } from '@mastra/core/storage';\nimport { DuckDBStore } from '@mastra/duckdb';\n\n/**\n * Age limits for the local trace store: 14 days for spans, metrics and logs,\n * 30 days for scores and feedback. Spans, logs and scores use the same windows\n * as libsql's `DEFAULT_RETENTION`, which has no metrics or feedback entries.\n */\nexport const LOCAL_OBSERVABILITY_RETENTION: RetentionConfig = {\n observability: {\n spans: { maxAge: '14d' },\n metrics: { maxAge: '14d' },\n logs: { maxAge: '14d' },\n scores: { maxAge: '30d' },\n feedback: { maxAge: '30d' },\n },\n};\n\n/** Upper bound on rows deleted per table per session, so startup pruning never runs long. */\nconst MAX_ROWS_PER_OPEN = 50_000;\n\nconst OBSERVABILITY_TABLES = ['span_events', 'metric_events', 'log_events', 'score_events', 'feedback_events'];\n\n/**\n * Prune only when every observability table already exists. A brand-new file\n * has no tables until the session composite runs init(), and pruning it would\n * log a missing-table error from the storage layer for a file with nothing to delete.\n */\nasync function pruneExistingTables(store: DuckDBStore): Promise<PruneResult[]> {\n const existing = await store.db.query<{ table_name: string }>(\n `SELECT table_name FROM information_schema.tables WHERE table_name IN (${OBSERVABILITY_TABLES.map(() => '?').join(', ')})`,\n OBSERVABILITY_TABLES,\n );\n if (existing.length < OBSERVABILITY_TABLES.length) return [];\n return store.prune({ maxRows: MAX_ROWS_PER_OPEN, pauseMs: 10 });\n}\n\n/**\n * Open the local observability DuckDB file used when `/observability local on`.\n * Connects eagerly so a lock error surfaces now, not mid-session, then prunes\n * aged events in the background so the file cannot grow without bound.\n * `pruned` never rejects; anything left over is pruned on the next open.\n */\nexport async function openLocalObservabilityStore(\n path: string,\n): Promise<{ store: DuckDBStore; pruned: Promise<PruneResult[]> }> {\n const store = new DuckDBStore({ id: 'mastra-code-observability', path, retention: LOCAL_OBSERVABILITY_RETENTION });\n await store.db.getConnection();\n // No init() here: the session composite initializes the domain.\n const pruned = pruneExistingTables(store).catch(() => []);\n return { store, pruned };\n}\n"],"mappings":";;;;;;;AAQA,MAAa,gCAAiD,EAC5D,eAAe;CACb,OAAO,EAAE,QAAQ,MAAM;CACvB,SAAS,EAAE,QAAQ,MAAM;CACzB,MAAM,EAAE,QAAQ,MAAM;CACtB,QAAQ,EAAE,QAAQ,MAAM;CACxB,UAAU,EAAE,QAAQ,MAAM;AAC5B,EACF;;AAGA,MAAM,oBAAoB;AAE1B,MAAM,uBAAuB;CAAC;CAAe;CAAiB;CAAc;CAAgB;AAAiB;;;;;;AAO7G,eAAe,oBAAoB,OAA4C;CAK7E,KAAI,MAJmB,MAAM,GAAG,MAC9B,yEAAyE,qBAAqB,UAAU,GAAG,CAAC,CAAC,KAAK,IAAI,EAAE,IACxH,oBACF,EAAA,CACa,SAAS,qBAAqB,QAAQ,OAAO,CAAC;CAC3D,OAAO,MAAM,MAAM;EAAE,SAAS;EAAmB,SAAS;CAAG,CAAC;AAChE;;;;;;;AAQA,eAAsB,4BACpB,MACiE;CACjE,MAAM,QAAQ,IAAI,YAAY;EAAE,IAAI;EAA6B;EAAM,WAAW;CAA8B,CAAC;CACjH,MAAM,MAAM,GAAG,cAAc;CAG7B,OAAO;EAAE;EAAO,QADD,oBAAoB,KAAK,CAAC,CAAC,YAAY,CAAC,CAClC;CAAE;AACzB"}
|