mastracode 0.34.0 → 0.35.0-alpha.1
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/CHANGELOG.md +44 -0
- package/README.md +51 -0
- package/dist/cli.cjs +64 -21
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +64 -21
- package/dist/cli.js.map +1 -1
- package/dist/process-memory-diagnostics-lifecycle.d.ts +4 -0
- package/dist/process-memory-diagnostics-lifecycle.d.ts.map +1 -0
- package/dist/tui/assistant-render-registry.d.ts +68 -0
- package/dist/tui/assistant-render-registry.d.ts.map +1 -0
- package/dist/tui/chat-boundary-reconciliation.d.ts.map +1 -1
- package/dist/tui/command-dispatch.d.ts.map +1 -1
- package/dist/tui/commands/clone.d.ts.map +1 -1
- package/dist/tui/commands/exit.d.ts.map +1 -1
- package/dist/tui/commands/index.d.ts +1 -0
- package/dist/tui/commands/index.d.ts.map +1 -1
- package/dist/tui/commands/new.d.ts.map +1 -1
- package/dist/tui/commands/profile.d.ts +5 -0
- package/dist/tui/commands/profile.d.ts.map +1 -0
- package/dist/tui/commands/prune.d.ts.map +1 -1
- package/dist/tui/commands/resource.d.ts.map +1 -1
- package/dist/tui/commands/settings.d.ts.map +1 -1
- package/dist/tui/commands/threads.d.ts.map +1 -1
- package/dist/tui/commands/types.d.ts +3 -0
- package/dist/tui/commands/types.d.ts.map +1 -1
- package/dist/tui/commands/update.d.ts.map +1 -1
- package/dist/tui/components/assistant-message.d.ts +20 -2
- package/dist/tui/components/assistant-message.d.ts.map +1 -1
- package/dist/tui/components/help-overlay.d.ts.map +1 -1
- package/dist/tui/handlers/agent-lifecycle.d.ts.map +1 -1
- package/dist/tui/handlers/message.d.ts.map +1 -1
- package/dist/tui/handlers/tool.d.ts.map +1 -1
- package/dist/tui/mastra-tui.d.ts +2 -0
- package/dist/tui/mastra-tui.d.ts.map +1 -1
- package/dist/tui/prune-chat.d.ts.map +1 -1
- package/dist/tui/render-messages.d.ts.map +1 -1
- package/dist/tui/render-scheduler.d.ts +5 -1
- package/dist/tui/render-scheduler.d.ts.map +1 -1
- package/dist/tui/setup.d.ts +2 -0
- package/dist/tui/setup.d.ts.map +1 -1
- package/dist/tui/state.d.ts +7 -0
- package/dist/tui/state.d.ts.map +1 -1
- package/dist/{tui-BB2N6Mud.js → tui-Cdxsbuqs.js} +1693 -1170
- package/dist/tui-Cdxsbuqs.js.map +1 -0
- package/dist/{tui-C6uUdh0u.cjs → tui-DNlKm3Lv.cjs} +1694 -1171
- package/dist/tui-DNlKm3Lv.cjs.map +1 -0
- package/dist/tui.cjs +1 -1
- package/dist/tui.js +1 -1
- package/package.json +13 -13
- package/dist/tui-BB2N6Mud.js.map +0 -1
- package/dist/tui-C6uUdh0u.cjs.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,49 @@
|
|
|
1
1
|
# mastracode
|
|
2
2
|
|
|
3
|
+
## 0.35.0-alpha.1
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Added environment-controlled process memory diagnostics for TUI and headless CLI sessions. The `/profile` command controls diagnostics interactively in the TUI. ([#21821](https://github.com/mastra-ai/mastra/pull/21821))
|
|
8
|
+
|
|
9
|
+
Enable diagnostics before startup:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
MASTRACODE_PROFILE=1 mastracode
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Control the same process-wide run from the TUI:
|
|
16
|
+
|
|
17
|
+
```text
|
|
18
|
+
/profile status
|
|
19
|
+
/profile start
|
|
20
|
+
/profile capture
|
|
21
|
+
/profile stop
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Diagnostics save private process and V8 samples, garbage collection events, and allocation profiles without forcing garbage collection or writing heap snapshots. Allocation profiles may contain prompts, credentials, file contents, and tool arguments, so keep them private and delete them after analysis.
|
|
25
|
+
|
|
26
|
+
### Patch Changes
|
|
27
|
+
|
|
28
|
+
- A slash command sent while the agent is working now shows the `steer` label right away, like a typed message does. It used to render unlabeled during the run and then come back labeled after a reload. ([#21842](https://github.com/mastra-ai/mastra/pull/21842))
|
|
29
|
+
|
|
30
|
+
- Improved Mastra Code memory usage and responsiveness during long streaming sessions. ([#21816](https://github.com/mastra-ai/mastra/pull/21816))
|
|
31
|
+
|
|
32
|
+
- Updated dependencies [[`d23e75d`](https://github.com/mastra-ai/mastra/commit/d23e75d57cc7cf5b9bfdbee896bf5a6a2484fed7), [`c8faa4e`](https://github.com/mastra-ai/mastra/commit/c8faa4e1cfebaec56b65e754e90b9fe46d153359), [`10de311`](https://github.com/mastra-ai/mastra/commit/10de311e93baea36468463d25bf0f97046239d5e), [`f2031a4`](https://github.com/mastra-ai/mastra/commit/f2031a47445e8f67a89ba1309036816f97ab7a65), [`4c2b973`](https://github.com/mastra-ai/mastra/commit/4c2b97396066e97c95c3d0429b2f63a92e6af127), [`8e529d4`](https://github.com/mastra-ai/mastra/commit/8e529d4ac754efef04b225841349e0da9edf89a6)]:
|
|
33
|
+
- @mastra/core@1.61.0-alpha.1
|
|
34
|
+
- @mastra/code-sdk@1.4.0-alpha.1
|
|
35
|
+
|
|
36
|
+
## 0.34.1-alpha.0
|
|
37
|
+
|
|
38
|
+
### Patch Changes
|
|
39
|
+
|
|
40
|
+
- Updated dependencies [[`88d14ca`](https://github.com/mastra-ai/mastra/commit/88d14cac008582a618fecc3d5c7fd3bdf4f6ddc3), [`84a5b69`](https://github.com/mastra-ai/mastra/commit/84a5b699f84d6bae0a34efe5a970d891090b9f41), [`84a5b69`](https://github.com/mastra-ai/mastra/commit/84a5b699f84d6bae0a34efe5a970d891090b9f41), [`64cd7ac`](https://github.com/mastra-ai/mastra/commit/64cd7ac22c2c7a6e6b533a4b3a9ede432700f1fb), [`84a5b69`](https://github.com/mastra-ai/mastra/commit/84a5b699f84d6bae0a34efe5a970d891090b9f41), [`038b7b4`](https://github.com/mastra-ai/mastra/commit/038b7b405cb4ac25ab3f3031334111b1f87ac112), [`4132d61`](https://github.com/mastra-ai/mastra/commit/4132d61f8367077120ee9e6420d3224dffd93c93)]:
|
|
41
|
+
- @mastra/core@1.60.1-alpha.0
|
|
42
|
+
- @mastra/libsql@1.21.1-alpha.0
|
|
43
|
+
- @mastra/pg@1.21.1-alpha.0
|
|
44
|
+
- @mastra/mcp@1.17.1-alpha.0
|
|
45
|
+
- @mastra/code-sdk@1.3.1-alpha.0
|
|
46
|
+
|
|
3
47
|
## 0.34.0
|
|
4
48
|
|
|
5
49
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -97,6 +97,7 @@ Select a suggestion with arrow keys and press Tab to insert it.
|
|
|
97
97
|
| `/diff` | Show modified files or git diff |
|
|
98
98
|
| `/name` | Rename current thread |
|
|
99
99
|
| `/cost` | Show token usage and estimated costs |
|
|
100
|
+
| `/profile` | Control process memory diagnostics |
|
|
100
101
|
| `/review` | Review a GitHub pull request |
|
|
101
102
|
| `/hooks` | Show/reload configured hooks |
|
|
102
103
|
| `/mcp` | Show/reload MCP server connections, disable or enable servers |
|
|
@@ -114,6 +115,56 @@ Select a suggestion with arrow keys and press Tab to insert it.
|
|
|
114
115
|
| `/help` | Show available commands |
|
|
115
116
|
| `/exit` | Exit the TUI |
|
|
116
117
|
|
|
118
|
+
### Process memory diagnostics
|
|
119
|
+
|
|
120
|
+
Enable process memory diagnostics before startup when you need evidence for memory growth in a long-running TUI or headless process:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
MASTRACODE_PROFILE=1 mastracode
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
> **Warning:** Allocation profiles can contain prompts, credentials, file contents, and tool arguments. Keep the output directory private, don't upload it as telemetry, and delete it after the investigation.
|
|
127
|
+
|
|
128
|
+
Use the same process-wide diagnostics instance from the TUI:
|
|
129
|
+
|
|
130
|
+
```text
|
|
131
|
+
/profile status
|
|
132
|
+
/profile start
|
|
133
|
+
/profile capture
|
|
134
|
+
/profile stop
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Bare `/profile` is an alias for `/profile status`. Starting an active run preserves its original directory and configuration. `capture` persists a Chrome allocation-sampling profile and starts a new sampling epoch. It doesn't force garbage collection (GC) or write a heap snapshot. `stop` writes a final sample and allocation profile before releasing the profiler.
|
|
138
|
+
|
|
139
|
+
#### Configuration
|
|
140
|
+
|
|
141
|
+
| Environment variable | Default | Minimum | Description |
|
|
142
|
+
| ---------------------------------------------- | --------------------------------- | ------- | ----------------------------------------------------------- |
|
|
143
|
+
| `MASTRACODE_PROFILE` | Disabled | N/A | Enables startup profiling for `1`, `true`, `yes`, or `on` |
|
|
144
|
+
| `MASTRACODE_PROFILE_DIR` | `<Mastra Code app-data>/profiles` | N/A | Parent directory for private, unique run directories |
|
|
145
|
+
| `MASTRACODE_PROFILE_SAMPLE_INTERVAL_MS` | `10000` | `1000` | Process and V8 sample interval in milliseconds |
|
|
146
|
+
| `MASTRACODE_PROFILE_CAPTURE_INTERVAL_MS` | `300000` | `10000` | Durable allocation-profile capture interval in milliseconds |
|
|
147
|
+
| `MASTRACODE_PROFILE_ALLOCATION_INTERVAL_BYTES` | `524288` | `32768` | V8 allocation-sampling interval in bytes |
|
|
148
|
+
|
|
149
|
+
Truthy values are case-insensitive and may contain surrounding whitespace. Other values leave startup profiling disabled. When startup profiling is enabled, invalid numeric values produce an actionable warning and leave Mastra Code running without an active profiler.
|
|
150
|
+
|
|
151
|
+
Each run gets a unique directory under the configured parent with these files:
|
|
152
|
+
|
|
153
|
+
- `metadata.json`: Immutable runtime and configuration metadata
|
|
154
|
+
- `process-samples.jsonl`: Append-only RSS, JavaScript heap, external memory, ArrayBuffer memory, resource usage, and V8 heap-space samples
|
|
155
|
+
- `gc-events.jsonl`: Append-only GC kind, flags, duration, and nearby memory values when V8 emits GC performance entries. A run can contain zero events.
|
|
156
|
+
- `allocation-<sequence>-<timestamp>.heapprofile`: Atomic Chrome allocation-sampling profiles
|
|
157
|
+
|
|
158
|
+
Mastra Code requests mode `0700` for run directories and `0600` for files on POSIX systems. Other platforms may apply permissions differently.
|
|
159
|
+
|
|
160
|
+
Compare JavaScript heap growth with resident set size (RSS). Rising heap-space usage points to retained JavaScript objects. Rising RSS with a stable JavaScript heap can point to external buffers, ArrayBuffers, native libraries, memory-mapped files, or allocator behavior. Allocation profiles include objects collected by major and minor GC, which helps distinguish sustained retention from transient allocation pressure.
|
|
161
|
+
|
|
162
|
+
Sampling and periodic file writes add overhead. Larger allocation intervals and longer capture intervals reduce it. Manual capture briefly rotates the sampling epoch.
|
|
163
|
+
|
|
164
|
+
Atomically completed captures survive later `SIGINT`, `SIGTERM`, `SIGHUP`, `SIGKILL`, or native crashes. The TUI writes a final capture for handled graceful signals and awaited fatal errors. Immediate `SIGKILL`, native crashes, power loss, and other abrupt termination can't guarantee a final capture, so the periodic capture interval protects those cases.
|
|
165
|
+
|
|
166
|
+
Delete the run directory when the investigation is complete. Never commit captured profiles.
|
|
167
|
+
|
|
117
168
|
### Dynamic workflows
|
|
118
169
|
|
|
119
170
|
Create a workflow by describing it in build-mode chat. For example:
|
package/dist/cli.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
const require_tui = require("./tui-
|
|
2
|
+
const require_tui = require("./tui-DNlKm3Lv.cjs");
|
|
3
3
|
let _mastra_code_sdk = require("@mastra/code-sdk");
|
|
4
4
|
let fs = require("fs");
|
|
5
5
|
fs = require_tui.__toESM(fs, 1);
|
|
@@ -8,12 +8,32 @@ let _mastra_code_sdk_error_classification = require("@mastra/code-sdk/error-clas
|
|
|
8
8
|
let _mastra_code_sdk_headless_index = require("@mastra/code-sdk/headless/index");
|
|
9
9
|
let _mastra_code_sdk_onboarding_settings = require("@mastra/code-sdk/onboarding/settings");
|
|
10
10
|
let _mastra_code_sdk_plugins_scaffold = require("@mastra/code-sdk/plugins/scaffold");
|
|
11
|
+
let _mastra_code_sdk_process_memory_diagnostics = require("@mastra/code-sdk/process-memory-diagnostics");
|
|
11
12
|
let _mastra_code_sdk_utils_debug_log = require("@mastra/code-sdk/utils/debug-log");
|
|
12
13
|
let _mastra_code_sdk_utils_stdin_pipe = require("@mastra/code-sdk/utils/stdin-pipe");
|
|
13
14
|
let _mastra_code_sdk_utils_thread_lock = require("@mastra/code-sdk/utils/thread-lock");
|
|
15
|
+
//#region src/process-memory-diagnostics-lifecycle.ts
|
|
16
|
+
async function startTuiProcessMemoryDiagnostics(env, warn, createSetup = _mastra_code_sdk_process_memory_diagnostics.createProcessMemoryDiagnosticsFromEnvironment) {
|
|
17
|
+
return (0, _mastra_code_sdk_process_memory_diagnostics.startConfiguredProcessMemoryDiagnostics)(createSetup(env), warn);
|
|
18
|
+
}
|
|
19
|
+
function createShutdownCoordinator(cleanup, exit, timeoutMs = 5e3) {
|
|
20
|
+
let shutdownPromise = null;
|
|
21
|
+
return (exitCode) => {
|
|
22
|
+
shutdownPromise ??= (async () => {
|
|
23
|
+
let timeout;
|
|
24
|
+
await Promise.race([cleanup().catch(() => void 0), new Promise((resolve) => {
|
|
25
|
+
timeout = setTimeout(resolve, timeoutMs);
|
|
26
|
+
})]);
|
|
27
|
+
if (timeout) clearTimeout(timeout);
|
|
28
|
+
exit(exitCode);
|
|
29
|
+
})();
|
|
30
|
+
return shutdownPromise;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
//#endregion
|
|
14
34
|
//#region src/version.ts
|
|
15
35
|
function getCurrentVersion() {
|
|
16
|
-
return "0.
|
|
36
|
+
return "0.35.0-alpha.1";
|
|
17
37
|
}
|
|
18
38
|
//#endregion
|
|
19
39
|
//#region src/main.ts
|
|
@@ -29,7 +49,9 @@ let storageMaintenance;
|
|
|
29
49
|
let stopPluginSignalProviders;
|
|
30
50
|
let analytics;
|
|
31
51
|
let tui;
|
|
52
|
+
let processMemoryDiagnostics;
|
|
32
53
|
let storageClosed = false;
|
|
54
|
+
let cleanupPromise = null;
|
|
33
55
|
function isTruthyEnv(name) {
|
|
34
56
|
return [
|
|
35
57
|
"1",
|
|
@@ -55,6 +77,9 @@ process.on("unhandledRejection", (reason) => {
|
|
|
55
77
|
});
|
|
56
78
|
async function tuiMain(pipedInput) {
|
|
57
79
|
const settings = (0, _mastra_code_sdk_onboarding_settings.loadSettings)();
|
|
80
|
+
processMemoryDiagnostics = await startTuiProcessMemoryDiagnostics(process.env, (warning) => {
|
|
81
|
+
console.info(`⚠ ${warning}`);
|
|
82
|
+
});
|
|
58
83
|
let browserPromise;
|
|
59
84
|
const loadBrowser = () => {
|
|
60
85
|
browserPromise ??= (0, _mastra_code_sdk_onboarding_settings.createBrowserFromSettings)(settings.browser);
|
|
@@ -110,11 +135,13 @@ async function tuiMain(pipedInput) {
|
|
|
110
135
|
mcpManager,
|
|
111
136
|
pluginManager: result.pluginManager,
|
|
112
137
|
storageMaintenance: result.storageMaintenance,
|
|
138
|
+
processMemoryDiagnostics,
|
|
113
139
|
knowledgeInspector: result.knowledgeInspector,
|
|
114
140
|
appName: "Mastra Code",
|
|
115
141
|
version: getCurrentVersion(),
|
|
116
142
|
inlineQuestions: true,
|
|
117
143
|
githubSignals: result.githubSignals,
|
|
144
|
+
exit: (exitCode) => void shutdownAndExit(exitCode),
|
|
118
145
|
...pipedInput ? { initialMessage: `The following was piped via stdin:\n\n${pipedInput}` } : {}
|
|
119
146
|
});
|
|
120
147
|
tui.run().catch((error) => {
|
|
@@ -126,23 +153,29 @@ async function tuiMain(pipedInput) {
|
|
|
126
153
|
session.state.set({ activeBrowserSettings: settings.browser }).catch(() => {});
|
|
127
154
|
}).catch(() => {});
|
|
128
155
|
}
|
|
129
|
-
const asyncCleanup =
|
|
130
|
-
(
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
156
|
+
const asyncCleanup = () => {
|
|
157
|
+
cleanupPromise ??= (async () => {
|
|
158
|
+
(0, _mastra_code_sdk_utils_thread_lock.releaseAllThreadLocks)();
|
|
159
|
+
try {
|
|
160
|
+
stopPluginSignalProviders?.();
|
|
161
|
+
} catch {}
|
|
162
|
+
const diagnosticsShutdown = processMemoryDiagnostics ? (0, _mastra_code_sdk_process_memory_diagnostics.stopProcessMemoryDiagnosticsWithTimeout)(processMemoryDiagnostics, (message) => console.warn(message)) : void 0;
|
|
163
|
+
const closeSignalsPubSub = signalsPubSub?.close;
|
|
164
|
+
await Promise.allSettled([
|
|
165
|
+
mcpManager?.disconnect(),
|
|
166
|
+
controller?.stopIntervals(),
|
|
167
|
+
closeSignalsPubSub?.()
|
|
168
|
+
]);
|
|
169
|
+
await Promise.allSettled([controller?.getMastra()?.shutdown(), analytics?.shutdown()]);
|
|
170
|
+
if (!storageClosed) {
|
|
171
|
+
storageClosed = true;
|
|
172
|
+
await storageMaintenance?.closeStorage?.().catch(() => {});
|
|
173
|
+
}
|
|
174
|
+
await diagnosticsShutdown;
|
|
175
|
+
})();
|
|
176
|
+
return cleanupPromise;
|
|
145
177
|
};
|
|
178
|
+
const shutdownAndExit = createShutdownCoordinator(asyncCleanup, (exitCode) => process.exit(exitCode));
|
|
146
179
|
process.on("beforeExit", () => {
|
|
147
180
|
asyncCleanup();
|
|
148
181
|
});
|
|
@@ -158,10 +191,11 @@ process.on("exit", () => {
|
|
|
158
191
|
(0, _mastra_code_sdk_utils_thread_lock.releaseAllThreadLocks)();
|
|
159
192
|
});
|
|
160
193
|
const handleTermSignal = () => {
|
|
194
|
+
asyncCleanup();
|
|
161
195
|
try {
|
|
162
196
|
tui?.stop();
|
|
163
197
|
} catch {}
|
|
164
|
-
|
|
198
|
+
shutdownAndExit(0);
|
|
165
199
|
};
|
|
166
200
|
process.on("SIGINT", handleTermSignal);
|
|
167
201
|
process.on("SIGTERM", handleTermSignal);
|
|
@@ -203,7 +237,12 @@ function handleFatalError(error) {
|
|
|
203
237
|
const write = (msg) => process.stderr.write(msg + "\n");
|
|
204
238
|
if (hasEconnrefused(error)) {
|
|
205
239
|
write(`\nFailed to connect to PostgreSQL at ${(0, _mastra_code_sdk_onboarding_settings.loadSettings)().storage?.pg?.connectionString ?? "localhost:5432"}.\nMake sure the database is running and accessible.\n\nTo switch back to LibSQL:\n Set MASTRA_STORAGE_BACKEND=libsql or change the backend in /settings\n`);
|
|
206
|
-
|
|
240
|
+
asyncCleanup();
|
|
241
|
+
try {
|
|
242
|
+
tui?.stop();
|
|
243
|
+
} catch {}
|
|
244
|
+
shutdownAndExit(1);
|
|
245
|
+
return;
|
|
207
246
|
}
|
|
208
247
|
const msg = `Fatal error: ${error instanceof Error ? error.message : String(error)}`;
|
|
209
248
|
write(msg);
|
|
@@ -212,7 +251,11 @@ function handleFatalError(error) {
|
|
|
212
251
|
fs.default.appendFileSync("/tmp/mastra-crash.log", crashLog);
|
|
213
252
|
} catch {}
|
|
214
253
|
if (error instanceof Error && error.stack) write(error.stack);
|
|
215
|
-
|
|
254
|
+
asyncCleanup();
|
|
255
|
+
try {
|
|
256
|
+
tui?.stop();
|
|
257
|
+
} catch {}
|
|
258
|
+
shutdownAndExit(1);
|
|
216
259
|
}
|
|
217
260
|
async function main() {
|
|
218
261
|
if (process.argv[2] === "plugin") return pluginMain(process.argv.slice(3));
|
package/dist/cli.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.cjs","names":["detectTerminalTheme","MastraTUI"],"sources":["../src/version.ts","../src/main.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\n\ndeclare const MASTRACODE_VERSION: string | undefined;\n\nexport function getCurrentVersion(): string {\n if (typeof MASTRACODE_VERSION !== 'undefined') {\n return MASTRACODE_VERSION;\n }\n\n const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')) as { version: string };\n return pkg.version;\n}\n","#!/usr/bin/env node\n/**\n * Main entry point for Mastra Code TUI.\n */\nimport fs from 'node:fs';\n\nimport { createMastraCode } from '@mastra/code-sdk';\nimport { createMastraCodeAnalytics } from '@mastra/code-sdk/analytics';\nimport { isStreamDestroyedError } from '@mastra/code-sdk/error-classification';\nimport { hasHeadlessFlag, runMCCli } from '@mastra/code-sdk/headless/index';\nimport { createBrowserFromSettings, loadSettings } from '@mastra/code-sdk/onboarding/settings';\nimport { formatScaffoldSuccess, scaffoldPlugin } from '@mastra/code-sdk/plugins/scaffold';\nimport { setupDebugLogging } from '@mastra/code-sdk/utils/debug-log';\nimport { drainPipedStdin, reopenStdinFromTTY } from '@mastra/code-sdk/utils/stdin-pipe';\nimport { releaseAllThreadLocks } from '@mastra/code-sdk/utils/thread-lock';\nimport { detectTerminalTheme } from './tui/detect-theme.js';\nimport { MastraTUI } from './tui/index.js';\nimport { applyThemeMode, restoreTerminalForeground } from './tui/theme.js';\nimport { getCurrentVersion } from './version.js';\n\nlet controller: Awaited<ReturnType<typeof createMastraCode>>['controller'];\nlet mcpManager: Awaited<ReturnType<typeof createMastraCode>>['mcpManager'];\nlet hookManager: Awaited<ReturnType<typeof createMastraCode>>['hookManager'];\nlet authStorage: Awaited<ReturnType<typeof createMastraCode>>['authStorage'];\nlet signalsPubSub: Awaited<ReturnType<typeof createMastraCode>>['signalsPubSub'];\nlet storageMaintenance: Awaited<ReturnType<typeof createMastraCode>>['storageMaintenance'];\nlet stopPluginSignalProviders: Awaited<ReturnType<typeof createMastraCode>>['stopPluginSignalProviders'] | undefined;\nlet analytics: ReturnType<typeof createMastraCodeAnalytics> | undefined;\nlet tui: MastraTUI | undefined;\nlet storageClosed = false;\n\nfunction isTruthyEnv(name: string): boolean {\n return ['1', 'true', 'yes', 'on'].includes(process.env[name]?.trim().toLowerCase() ?? '');\n}\n\nfunction resolveInitialStateFromEnv() {\n const currentModelId = process.env.MASTRACODE_MODEL_ID?.trim();\n const initialState: Record<string, unknown> = {};\n if (currentModelId) initialState.currentModelId = currentModelId;\n if (isTruthyEnv('MASTRACODE_YOLO')) initialState.yolo = true;\n return Object.keys(initialState).length > 0 ? initialState : undefined;\n}\n\n// Global safety nets — catch any uncaught errors from storage init, etc.\nprocess.on('uncaughtException', error => {\n // ERR_STREAM_DESTROYED is non-fatal — happens routinely when streams close\n // during shutdown, cancelled LLM requests, or LSP/subprocess exits (#13548, #13549)\n if (isStreamDestroyedError(error)) return;\n handleFatalError(error);\n});\nprocess.on('unhandledRejection', reason => {\n if (isStreamDestroyedError(reason)) return;\n handleFatalError(reason instanceof Error ? reason : new Error(String(reason)));\n});\n\nasync function tuiMain(pipedInput?: string | null) {\n const settings = loadSettings();\n let browserPromise: ReturnType<typeof createBrowserFromSettings> | undefined;\n const loadBrowser = () => {\n browserPromise ??= createBrowserFromSettings(settings.browser);\n return browserPromise;\n };\n\n const initialState = resolveInitialStateFromEnv();\n const result = await createMastraCode({\n unixSocketPubSub: !isTruthyEnv('MASTRACODE_DISABLE_UNIX_SOCKET_PUBSUB'),\n disableMcp: isTruthyEnv('MASTRACODE_DISABLE_MCP'),\n disableHooks: isTruthyEnv('MASTRACODE_DISABLE_HOOKS'),\n ...(isTruthyEnv('MASTRACODE_DISABLE_MEMORY') ? { memory: false as never } : {}),\n ...(initialState ? { initialState: initialState as never } : {}),\n });\n controller = result.controller;\n mcpManager = result.mcpManager;\n hookManager = result.hookManager;\n authStorage = result.authStorage;\n signalsPubSub = result.signalsPubSub;\n storageMaintenance = result.storageMaintenance;\n stopPluginSignalProviders = result.stopPluginSignalProviders;\n\n if (result.storageWarning) {\n console.info(`⚠ ${result.storageWarning}`);\n }\n if (result.observabilityWarning) {\n console.info(`⚠ ${result.observabilityWarning}`);\n }\n\n // MCP connection is deferred to TUI.init() (after ui.start()) so that\n // status messages use showInfo() instead of console.info(), which would\n // corrupt the terminal. Headless mode still inits from headless/cli.ts.\n\n setupDebugLogging();\n\n // Detect and apply terminal theme\n // MASTRA_THEME env var is the highest-priority override\n const envTheme = process.env.MASTRA_THEME?.toLowerCase();\n let themeMode: 'dark' | 'light';\n let detectedBgHex: string | undefined;\n if (envTheme === 'dark' || envTheme === 'light') {\n themeMode = envTheme;\n } else {\n const settings = loadSettings();\n const themePref = settings.preferences.theme;\n if (themePref === 'dark' || themePref === 'light') {\n themeMode = themePref;\n } else {\n const detection = await detectTerminalTheme();\n themeMode = detection.mode;\n detectedBgHex = detection.detectedBgHex;\n }\n }\n applyThemeMode(themeMode, detectedBgHex);\n\n // createMastraCode() brought up shared resources and minted the single\n // session that all work runs through. The AgentController owns no session of its own.\n const session = result.session;\n\n analytics = createMastraCodeAnalytics({ version: getCurrentVersion() });\n analytics.capture('mastracode_session_started', {\n mode: session.mode.get(),\n resourceId: session.identity.getResourceId(),\n hasAuthStorage: Boolean(authStorage),\n hasMcp: Boolean(mcpManager),\n theme: themeMode,\n });\n\n tui = new MastraTUI({\n controller: controller,\n session,\n hookManager,\n analytics,\n authStorage,\n mcpManager,\n pluginManager: result.pluginManager,\n storageMaintenance: result.storageMaintenance,\n knowledgeInspector: result.knowledgeInspector,\n appName: 'Mastra Code',\n version: getCurrentVersion(),\n inlineQuestions: true,\n githubSignals: result.githubSignals,\n ...(pipedInput ? { initialMessage: `The following was piped via stdin:\\n\\n${pipedInput}` } : {}),\n });\n tui.run().catch(error => {\n handleFatalError(error);\n });\n\n if (settings.browser.enabled) {\n void loadBrowser()\n .then(browser => {\n if (!browser) return;\n controller.setBrowser(browser);\n void session.state.set({ activeBrowserSettings: settings.browser } as any).catch(() => {});\n })\n .catch(() => {});\n }\n}\n\nconst asyncCleanup = async () => {\n releaseAllThreadLocks();\n // Stop plugin-contributed signal providers (and the plugin reload listener)\n // before quiescing workers: a provider that keeps polling past this point\n // could dispatch into a controller that is shutting down.\n try {\n stopPluginSignalProviders?.();\n } catch {\n // Best-effort — the process is exiting.\n }\n const closeSignalsPubSub = (signalsPubSub as { close?: () => Promise<void> | void } | undefined)?.close;\n await Promise.allSettled([mcpManager?.disconnect(), controller?.stopIntervals(), closeSignalsPubSub?.()]);\n // Mastra owns the workspaces and must destroy them to stop retained language\n // servers before storage is closed.\n await Promise.allSettled([controller?.getMastra()?.shutdown(), analytics?.shutdown()]);\n // Checkpoint WAL and close the local storage connection after all producers\n // and timers are quiesced. Idempotent — repeated signals (SIGINT then SIGHUP)\n // close only once. LibSQLStore.close()/LibSQLVector.close() truncate the WAL\n // and switch back to DELETE journal mode for a clean shutdown.\n if (!storageClosed) {\n storageClosed = true;\n await storageMaintenance?.closeStorage?.().catch(() => {\n // Swallow — best-effort cleanup during shutdown. The process is exiting.\n });\n }\n};\n\nprocess.on('beforeExit', () => {\n void asyncCleanup();\n});\nprocess.on('exit', () => {\n // Ensure terminal protocols (kitty keyboard, modifyOtherKeys, bracketed paste,\n // raw mode) are disabled on ANY exit path. Without this, killing the process\n // via SIGINT/SIGTERM leaves the terminal in a corrupted state where keypresses\n // produce escape sequences like \"5;99~\" instead of normal characters.\n try {\n tui?.stop();\n } catch {\n // Failsafe: even if MastraTUI.stop() throws, write raw terminal reset\n // sequences to disable Kitty keyboard protocol, bracketed paste, and\n // modifyOtherKeys. These are the exact sequences pi-tui's terminal.stop()\n // would write.\n }\n // Belt-and-suspenders: always write terminal reset sequences directly,\n // regardless of whether tui.stop() succeeded. Writing them twice is harmless\n // but missing them leaves the terminal in a corrupted state.\n try {\n process.stdout.write(\n '\\x1b[?2004l' + // disable bracketed paste\n '\\x1b[<u' + // pop kitty keyboard protocol\n '\\x1b[>4;0m' + // disable modifyOtherKeys\n '\\x1b[?25h', // show cursor\n );\n if (process.stdin.setRawMode) {\n process.stdin.setRawMode(false);\n }\n } catch {\n // stdout may already be closed during exit\n }\n restoreTerminalForeground();\n releaseAllThreadLocks();\n});\n\n// For all termination signals: stop the TUI FIRST (synchronous, disables keyboard\n// protocol immediately) before doing any async cleanup. This ensures the terminal\n// escape sequences are written even if asyncCleanup hangs or the process is killed\n// during cleanup.\nconst handleTermSignal = () => {\n try {\n tui?.stop();\n } catch {\n // ignored — exit handler has failsafe reset\n }\n void asyncCleanup().finally(() => process.exit(0));\n};\nprocess.on('SIGINT', handleTermSignal);\nprocess.on('SIGTERM', handleTermSignal);\nprocess.on('SIGHUP', handleTermSignal);\n\nfunction hasEconnrefused(err: unknown, depth = 0): boolean {\n if (!err || depth > 5) return false;\n const e = err as any;\n if (e.code === 'ECONNREFUSED') return true;\n if (e.cause) return hasEconnrefused(e.cause, depth + 1);\n // AggregateError has .errors array\n if (Array.isArray(e.errors)) return e.errors.some((inner: unknown) => hasEconnrefused(inner, depth + 1));\n return false;\n}\n\nfunction pluginMain(args: string[]): void {\n if (args[0] !== 'scaffold') {\n process.stderr.write('Usage: mastracode plugin scaffold <dir> [--id acme.foo] [--name \"Foo Tools\"]\\n');\n process.exit(1);\n }\n\n const dir = args[1];\n if (!dir) {\n process.stderr.write('Usage: mastracode plugin scaffold <dir> [--id acme.foo] [--name \"Foo Tools\"]\\n');\n process.exit(1);\n }\n\n const id = readFlag(args, '--id');\n const name = readFlag(args, '--name');\n const targetDir = scaffoldPlugin(dir, { ...(id ? { id } : {}), ...(name ? { name } : {}) });\n process.stdout.write(`${formatScaffoldSuccess(targetDir)}\\n`);\n}\n\nfunction readFlag(args: string[], flag: string): string | undefined {\n const index = args.indexOf(flag);\n if (index === -1) return undefined;\n const value = args[index + 1];\n if (!value || value.startsWith('--')) {\n throw new Error(`Missing value for ${flag}`);\n }\n return value;\n}\n\nfunction handleFatalError(error: unknown): never {\n // Always write to real stderr, even if console.error was overridden\n const write = (msg: string) => process.stderr.write(msg + '\\n');\n\n if (hasEconnrefused(error)) {\n const settings = loadSettings();\n const connStr = settings.storage?.pg?.connectionString;\n const target = connStr ?? 'localhost:5432';\n write(\n `\\nFailed to connect to PostgreSQL at ${target}.` +\n `\\nMake sure the database is running and accessible.` +\n `\\n\\nTo switch back to LibSQL:` +\n `\\n Set MASTRA_STORAGE_BACKEND=libsql or change the backend in /settings\\n`,\n );\n process.exit(1);\n }\n\n const msg = `Fatal error: ${error instanceof Error ? error.message : String(error)}`;\n write(msg);\n // Write crash log to file so it persists even if terminal closes\n try {\n const crashLog = `[${new Date().toISOString()}] ${msg}\\n${error instanceof Error && error.stack ? error.stack + '\\n' : ''}`;\n fs.appendFileSync('/tmp/mastra-crash.log', crashLog);\n } catch {}\n if (error instanceof Error && error.stack) {\n write(error.stack);\n }\n process.exit(1);\n}\n\nasync function main() {\n if (process.argv[2] === 'plugin') {\n return pluginMain(process.argv.slice(3));\n }\n\n if (hasHeadlessFlag(process.argv) || process.argv.includes('--help') || process.argv.includes('-h')) {\n return runMCCli();\n }\n\n if (process.argv.includes('--acp')) {\n const { acpMain } = await import('@mastra/code-sdk/acp/index');\n return acpMain({ dangerousAutoApprove: process.argv.includes('--dangerous-auto-approve') });\n }\n\n // When stdin is piped (e.g. `cat foo | mastracode`), drain the pipe fully\n // before starting the TUI. The drain blocks until the sender process exits\n // and closes its stdout, so we never see partial output.\n let pipedInput: string | null = null;\n if (!process.stdin.isTTY) {\n process.stderr.write('Reading piped input...\\n');\n pipedInput = await drainPipedStdin();\n\n // Always reopen a real TTY — even if the pipe was empty, the original\n // stdin is consumed/closed and the TUI needs a live TTY for keyboard input.\n const reopenedStdin = reopenStdinFromTTY();\n if (!reopenedStdin) {\n process.stderr.write('No TTY available — falling back to headless mode.\\n');\n return runMCCli(pipedInput);\n }\n }\n\n return tuiMain(pipedInput);\n}\n\nmain().catch(error => {\n handleFatalError(error);\n});\n"],"mappings":";;;;;;;;;;;;;;AAIA,SAAgB,oBAA4B;CAExC,OAAA;AAKJ;;;;;;ACSA,IAAI;AACJ,IAAI;AACJ,IAAI;AACJ,IAAI;AACJ,IAAI;AACJ,IAAI;AACJ,IAAI;AACJ,IAAI;AACJ,IAAI;AACJ,IAAI,gBAAgB;AAEpB,SAAS,YAAY,MAAuB;CAC1C,OAAO;EAAC;EAAK;EAAQ;EAAO;CAAI,CAAC,CAAC,SAAS,QAAQ,IAAI,KAAK,EAAE,KAAK,CAAC,CAAC,YAAY,KAAK,EAAE;AAC1F;AAEA,SAAS,6BAA6B;CACpC,MAAM,iBAAiB,QAAQ,IAAI,qBAAqB,KAAK;CAC7D,MAAM,eAAwC,CAAC;CAC/C,IAAI,gBAAgB,aAAa,iBAAiB;CAClD,IAAI,YAAY,iBAAiB,GAAG,aAAa,OAAO;CACxD,OAAO,OAAO,KAAK,YAAY,CAAC,CAAC,SAAS,IAAI,eAAe,KAAA;AAC/D;AAGA,QAAQ,GAAG,sBAAqB,UAAS;CAGvC,KAAA,GAAA,sCAAA,uBAAA,CAA2B,KAAK,GAAG;CACnC,iBAAiB,KAAK;AACxB,CAAC;AACD,QAAQ,GAAG,uBAAsB,WAAU;CACzC,KAAA,GAAA,sCAAA,uBAAA,CAA2B,MAAM,GAAG;CACpC,iBAAiB,kBAAkB,QAAQ,SAAS,IAAI,MAAM,OAAO,MAAM,CAAC,CAAC;AAC/E,CAAC;AAED,eAAe,QAAQ,YAA4B;CACjD,MAAM,YAAA,GAAA,qCAAA,aAAA,CAAwB;CAC9B,IAAI;CACJ,MAAM,oBAAoB;EACxB,oBAAA,GAAA,qCAAA,0BAAA,CAA6C,SAAS,OAAO;EAC7D,OAAO;CACT;CAEA,MAAM,eAAe,2BAA2B;CAChD,MAAM,SAAS,OAAA,GAAA,iBAAA,iBAAA,CAAuB;EACpC,kBAAkB,CAAC,YAAY,uCAAuC;EACtE,YAAY,YAAY,wBAAwB;EAChD,cAAc,YAAY,0BAA0B;EACpD,GAAI,YAAY,2BAA2B,IAAI,EAAE,QAAQ,MAAe,IAAI,CAAC;EAC7E,GAAI,eAAe,EAAgB,aAAsB,IAAI,CAAC;CAChE,CAAC;CACD,aAAa,OAAO;CACpB,aAAa,OAAO;CACpB,cAAc,OAAO;CACrB,cAAc,OAAO;CACrB,gBAAgB,OAAO;CACvB,qBAAqB,OAAO;CAC5B,4BAA4B,OAAO;CAEnC,IAAI,OAAO,gBACT,QAAQ,KAAK,KAAK,OAAO,gBAAgB;CAE3C,IAAI,OAAO,sBACT,QAAQ,KAAK,KAAK,OAAO,sBAAsB;CAOjD,CAAA,GAAA,iCAAA,kBAAA,CAAkB;CAIlB,MAAM,WAAW,QAAQ,IAAI,cAAc,YAAY;CACvD,IAAI;CACJ,IAAI;CACJ,IAAI,aAAa,UAAU,aAAa,SACtC,YAAY;MACP;EAEL,MAAM,aAAA,GAAA,qCAAA,aAAA,CAAmB,CAAC,CAAC,YAAY;EACvC,IAAI,cAAc,UAAU,cAAc,SACxC,YAAY;OACP;GACL,MAAM,YAAY,MAAMA,YAAAA,oBAAoB;GAC5C,YAAY,UAAU;GACtB,gBAAgB,UAAU;EAC5B;CACF;CACA,YAAA,eAAe,WAAW,aAAa;CAIvC,MAAM,UAAU,OAAO;CAEvB,aAAA,GAAA,2BAAA,0BAAA,CAAsC,EAAE,SAAS,kBAAkB,EAAE,CAAC;CACtE,UAAU,QAAQ,8BAA8B;EAC9C,MAAM,QAAQ,KAAK,IAAI;EACvB,YAAY,QAAQ,SAAS,cAAc;EAC3C,gBAAgB,QAAQ,WAAW;EACnC,QAAQ,QAAQ,UAAU;EAC1B,OAAO;CACT,CAAC;CAED,MAAM,IAAIC,YAAAA,UAAU;EACN;EACZ;EACA;EACA;EACA;EACA;EACA,eAAe,OAAO;EACtB,oBAAoB,OAAO;EAC3B,oBAAoB,OAAO;EAC3B,SAAS;EACT,SAAS,kBAAkB;EAC3B,iBAAiB;EACjB,eAAe,OAAO;EACtB,GAAI,aAAa,EAAE,gBAAgB,yCAAyC,aAAa,IAAI,CAAC;CAChG,CAAC;CACD,IAAI,IAAI,CAAC,CAAC,OAAM,UAAS;EACvB,iBAAiB,KAAK;CACxB,CAAC;CAED,IAAI,SAAS,QAAQ,SACnB,YAAiB,CAAC,CACf,MAAK,YAAW;EACf,IAAI,CAAC,SAAS;EACd,WAAW,WAAW,OAAO;EAC7B,QAAa,MAAM,IAAI,EAAE,uBAAuB,SAAS,QAAQ,CAAQ,CAAC,CAAC,YAAY,CAAC,CAAC;CAC3F,CAAC,CAAC,CACD,YAAY,CAAC,CAAC;AAErB;AAEA,MAAM,eAAe,YAAY;CAC/B,CAAA,GAAA,mCAAA,sBAAA,CAAsB;CAItB,IAAI;EACF,4BAA4B;CAC9B,QAAQ,CAER;CACA,MAAM,qBAAsB,eAAsE;CAClG,MAAM,QAAQ,WAAW;EAAC,YAAY,WAAW;EAAG,YAAY,cAAc;EAAG,qBAAqB;CAAC,CAAC;CAGxG,MAAM,QAAQ,WAAW,CAAC,YAAY,UAAU,CAAC,EAAE,SAAS,GAAG,WAAW,SAAS,CAAC,CAAC;CAKrF,IAAI,CAAC,eAAe;EAClB,gBAAgB;EAChB,MAAM,oBAAoB,eAAe,CAAC,CAAC,YAAY,CAEvD,CAAC;CACH;AACF;AAEA,QAAQ,GAAG,oBAAoB;CAC7B,aAAkB;AACpB,CAAC;AACD,QAAQ,GAAG,cAAc;CAKvB,IAAI;EACF,KAAK,KAAK;CACZ,QAAQ,CAKR;CAIA,IAAI;EACF,QAAQ,OAAO,MACb,uCAIF;EACA,IAAI,QAAQ,MAAM,YAChB,QAAQ,MAAM,WAAW,KAAK;CAElC,QAAQ,CAER;CACA,YAAA,0BAA0B;CAC1B,CAAA,GAAA,mCAAA,sBAAA,CAAsB;AACxB,CAAC;AAMD,MAAM,yBAAyB;CAC7B,IAAI;EACF,KAAK,KAAK;CACZ,QAAQ,CAER;CACA,aAAkB,CAAC,CAAC,cAAc,QAAQ,KAAK,CAAC,CAAC;AACnD;AACA,QAAQ,GAAG,UAAU,gBAAgB;AACrC,QAAQ,GAAG,WAAW,gBAAgB;AACtC,QAAQ,GAAG,UAAU,gBAAgB;AAErC,SAAS,gBAAgB,KAAc,QAAQ,GAAY;CACzD,IAAI,CAAC,OAAO,QAAQ,GAAG,OAAO;CAC9B,MAAM,IAAI;CACV,IAAI,EAAE,SAAS,gBAAgB,OAAO;CACtC,IAAI,EAAE,OAAO,OAAO,gBAAgB,EAAE,OAAO,QAAQ,CAAC;CAEtD,IAAI,MAAM,QAAQ,EAAE,MAAM,GAAG,OAAO,EAAE,OAAO,MAAM,UAAmB,gBAAgB,OAAO,QAAQ,CAAC,CAAC;CACvG,OAAO;AACT;AAEA,SAAS,WAAW,MAAsB;CACxC,IAAI,KAAK,OAAO,YAAY;EAC1B,QAAQ,OAAO,MAAM,kFAAgF;EACrG,QAAQ,KAAK,CAAC;CAChB;CAEA,MAAM,MAAM,KAAK;CACjB,IAAI,CAAC,KAAK;EACR,QAAQ,OAAO,MAAM,kFAAgF;EACrG,QAAQ,KAAK,CAAC;CAChB;CAEA,MAAM,KAAK,SAAS,MAAM,MAAM;CAChC,MAAM,OAAO,SAAS,MAAM,QAAQ;CACpC,MAAM,aAAA,GAAA,kCAAA,eAAA,CAA2B,KAAK;EAAE,GAAI,KAAK,EAAE,GAAG,IAAI,CAAC;EAAI,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;CAAG,CAAC;CAC1F,QAAQ,OAAO,MAAM,IAAA,GAAA,kCAAA,sBAAA,CAAyB,SAAS,EAAE,GAAG;AAC9D;AAEA,SAAS,SAAS,MAAgB,MAAkC;CAClE,MAAM,QAAQ,KAAK,QAAQ,IAAI;CAC/B,IAAI,UAAU,IAAI,OAAO,KAAA;CACzB,MAAM,QAAQ,KAAK,QAAQ;CAC3B,IAAI,CAAC,SAAS,MAAM,WAAW,IAAI,GACjC,MAAM,IAAI,MAAM,qBAAqB,MAAM;CAE7C,OAAO;AACT;AAEA,SAAS,iBAAiB,OAAuB;CAE/C,MAAM,SAAS,QAAgB,QAAQ,OAAO,MAAM,MAAM,IAAI;CAE9D,IAAI,gBAAgB,KAAK,GAAG;EAI1B,MACE,yCAAA,GAAA,qCAAA,aAAA,CAHqB,CAAC,CAAC,SAAS,IAAI,oBACZ,iBAEuB,4JAIjD;EACA,QAAQ,KAAK,CAAC;CAChB;CAEA,MAAM,MAAM,gBAAgB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;CACjF,MAAM,GAAG;CAET,IAAI;EACF,MAAM,WAAW,qBAAI,IAAI,KAAK,EAAA,CAAE,YAAY,EAAE,IAAI,IAAI,IAAI,iBAAiB,SAAS,MAAM,QAAQ,MAAM,QAAQ,OAAO;EACvH,GAAA,QAAG,eAAe,yBAAyB,QAAQ;CACrD,QAAQ,CAAC;CACT,IAAI,iBAAiB,SAAS,MAAM,OAClC,MAAM,MAAM,KAAK;CAEnB,QAAQ,KAAK,CAAC;AAChB;AAEA,eAAe,OAAO;CACpB,IAAI,QAAQ,KAAK,OAAO,UACtB,OAAO,WAAW,QAAQ,KAAK,MAAM,CAAC,CAAC;CAGzC,KAAA,GAAA,gCAAA,gBAAA,CAAoB,QAAQ,IAAI,KAAK,QAAQ,KAAK,SAAS,QAAQ,KAAK,QAAQ,KAAK,SAAS,IAAI,GAChG,QAAA,GAAA,gCAAA,SAAA,CAAgB;CAGlB,IAAI,QAAQ,KAAK,SAAS,OAAO,GAAG;EAClC,MAAM,EAAE,YAAY,MAAM,OAAO;EACjC,OAAO,QAAQ,EAAE,sBAAsB,QAAQ,KAAK,SAAS,0BAA0B,EAAE,CAAC;CAC5F;CAKA,IAAI,aAA4B;CAChC,IAAI,CAAC,QAAQ,MAAM,OAAO;EACxB,QAAQ,OAAO,MAAM,0BAA0B;EAC/C,aAAa,OAAA,GAAA,kCAAA,gBAAA,CAAsB;EAKnC,IAAI,EAAA,GAAA,kCAAA,mBAAA,CAAa,GAAG;GAClB,QAAQ,OAAO,MAAM,qDAAqD;GAC1E,QAAA,GAAA,gCAAA,SAAA,CAAgB,UAAU;EAC5B;CACF;CAEA,OAAO,QAAQ,UAAU;AAC3B;AAEA,KAAK,CAAC,CAAC,OAAM,UAAS;CACpB,iBAAiB,KAAK;AACxB,CAAC"}
|
|
1
|
+
{"version":3,"file":"cli.cjs","names":["createProcessMemoryDiagnosticsFromEnvironment","detectTerminalTheme","MastraTUI"],"sources":["../src/process-memory-diagnostics-lifecycle.ts","../src/version.ts","../src/main.ts"],"sourcesContent":["import {\n createProcessMemoryDiagnosticsFromEnvironment,\n startConfiguredProcessMemoryDiagnostics,\n type ProcessMemoryDiagnostics,\n type ProcessMemoryDiagnosticsEnvironment,\n type ProcessMemoryDiagnosticsSetup,\n} from '@mastra/code-sdk/process-memory-diagnostics';\n\nexport async function startTuiProcessMemoryDiagnostics(\n env: ProcessMemoryDiagnosticsEnvironment,\n warn: (message: string) => void,\n createSetup: (\n env: ProcessMemoryDiagnosticsEnvironment,\n ) => ProcessMemoryDiagnosticsSetup = createProcessMemoryDiagnosticsFromEnvironment,\n): Promise<ProcessMemoryDiagnostics> {\n return startConfiguredProcessMemoryDiagnostics(createSetup(env), warn);\n}\n\nexport function createShutdownCoordinator(\n cleanup: () => Promise<void>,\n exit: (exitCode: number) => never,\n timeoutMs = 5_000,\n): (exitCode: number) => Promise<void> {\n let shutdownPromise: Promise<void> | null = null;\n return exitCode => {\n shutdownPromise ??= (async () => {\n let timeout: ReturnType<typeof setTimeout> | undefined;\n await Promise.race([\n cleanup().catch(() => undefined),\n new Promise<void>(resolve => {\n timeout = setTimeout(resolve, timeoutMs);\n }),\n ]);\n if (timeout) clearTimeout(timeout);\n exit(exitCode);\n })();\n return shutdownPromise;\n };\n}\n","import { readFileSync } from 'node:fs';\n\ndeclare const MASTRACODE_VERSION: string | undefined;\n\nexport function getCurrentVersion(): string {\n if (typeof MASTRACODE_VERSION !== 'undefined') {\n return MASTRACODE_VERSION;\n }\n\n const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')) as { version: string };\n return pkg.version;\n}\n","#!/usr/bin/env node\n/**\n * Main entry point for Mastra Code TUI.\n */\nimport fs from 'node:fs';\n\nimport { createMastraCode } from '@mastra/code-sdk';\nimport { createMastraCodeAnalytics } from '@mastra/code-sdk/analytics';\nimport { isStreamDestroyedError } from '@mastra/code-sdk/error-classification';\nimport { hasHeadlessFlag, runMCCli } from '@mastra/code-sdk/headless/index';\nimport { createBrowserFromSettings, loadSettings } from '@mastra/code-sdk/onboarding/settings';\nimport { formatScaffoldSuccess, scaffoldPlugin } from '@mastra/code-sdk/plugins/scaffold';\nimport {\n stopProcessMemoryDiagnosticsWithTimeout,\n type ProcessMemoryDiagnostics,\n} from '@mastra/code-sdk/process-memory-diagnostics';\nimport { setupDebugLogging } from '@mastra/code-sdk/utils/debug-log';\nimport { drainPipedStdin, reopenStdinFromTTY } from '@mastra/code-sdk/utils/stdin-pipe';\nimport { releaseAllThreadLocks } from '@mastra/code-sdk/utils/thread-lock';\nimport { createShutdownCoordinator, startTuiProcessMemoryDiagnostics } from './process-memory-diagnostics-lifecycle.js';\nimport { detectTerminalTheme } from './tui/detect-theme.js';\nimport { MastraTUI } from './tui/index.js';\nimport { applyThemeMode, restoreTerminalForeground } from './tui/theme.js';\nimport { getCurrentVersion } from './version.js';\n\nlet controller: Awaited<ReturnType<typeof createMastraCode>>['controller'];\nlet mcpManager: Awaited<ReturnType<typeof createMastraCode>>['mcpManager'];\nlet hookManager: Awaited<ReturnType<typeof createMastraCode>>['hookManager'];\nlet authStorage: Awaited<ReturnType<typeof createMastraCode>>['authStorage'];\nlet signalsPubSub: Awaited<ReturnType<typeof createMastraCode>>['signalsPubSub'];\nlet storageMaintenance: Awaited<ReturnType<typeof createMastraCode>>['storageMaintenance'];\nlet stopPluginSignalProviders: Awaited<ReturnType<typeof createMastraCode>>['stopPluginSignalProviders'] | undefined;\nlet analytics: ReturnType<typeof createMastraCodeAnalytics> | undefined;\nlet tui: MastraTUI | undefined;\nlet processMemoryDiagnostics: ProcessMemoryDiagnostics | undefined;\nlet storageClosed = false;\nlet cleanupPromise: Promise<void> | null = null;\n\nfunction isTruthyEnv(name: string): boolean {\n return ['1', 'true', 'yes', 'on'].includes(process.env[name]?.trim().toLowerCase() ?? '');\n}\n\nfunction resolveInitialStateFromEnv() {\n const currentModelId = process.env.MASTRACODE_MODEL_ID?.trim();\n const initialState: Record<string, unknown> = {};\n if (currentModelId) initialState.currentModelId = currentModelId;\n if (isTruthyEnv('MASTRACODE_YOLO')) initialState.yolo = true;\n return Object.keys(initialState).length > 0 ? initialState : undefined;\n}\n\n// Global safety nets — catch any uncaught errors from storage init, etc.\nprocess.on('uncaughtException', error => {\n // ERR_STREAM_DESTROYED is non-fatal — happens routinely when streams close\n // during shutdown, cancelled LLM requests, or LSP/subprocess exits (#13548, #13549)\n if (isStreamDestroyedError(error)) return;\n handleFatalError(error);\n});\nprocess.on('unhandledRejection', reason => {\n if (isStreamDestroyedError(reason)) return;\n handleFatalError(reason instanceof Error ? reason : new Error(String(reason)));\n});\n\nasync function tuiMain(pipedInput?: string | null) {\n const settings = loadSettings();\n processMemoryDiagnostics = await startTuiProcessMemoryDiagnostics(process.env, warning => {\n console.info(`⚠ ${warning}`);\n });\n let browserPromise: ReturnType<typeof createBrowserFromSettings> | undefined;\n const loadBrowser = () => {\n browserPromise ??= createBrowserFromSettings(settings.browser);\n return browserPromise;\n };\n\n const initialState = resolveInitialStateFromEnv();\n const result = await createMastraCode({\n unixSocketPubSub: !isTruthyEnv('MASTRACODE_DISABLE_UNIX_SOCKET_PUBSUB'),\n disableMcp: isTruthyEnv('MASTRACODE_DISABLE_MCP'),\n disableHooks: isTruthyEnv('MASTRACODE_DISABLE_HOOKS'),\n ...(isTruthyEnv('MASTRACODE_DISABLE_MEMORY') ? { memory: false as never } : {}),\n ...(initialState ? { initialState: initialState as never } : {}),\n });\n controller = result.controller;\n mcpManager = result.mcpManager;\n hookManager = result.hookManager;\n authStorage = result.authStorage;\n signalsPubSub = result.signalsPubSub;\n storageMaintenance = result.storageMaintenance;\n stopPluginSignalProviders = result.stopPluginSignalProviders;\n\n if (result.storageWarning) {\n console.info(`⚠ ${result.storageWarning}`);\n }\n if (result.observabilityWarning) {\n console.info(`⚠ ${result.observabilityWarning}`);\n }\n\n // MCP connection is deferred to TUI.init() (after ui.start()) so that\n // status messages use showInfo() instead of console.info(), which would\n // corrupt the terminal. Headless mode still inits from headless/cli.ts.\n\n setupDebugLogging();\n\n // Detect and apply terminal theme\n // MASTRA_THEME env var is the highest-priority override\n const envTheme = process.env.MASTRA_THEME?.toLowerCase();\n let themeMode: 'dark' | 'light';\n let detectedBgHex: string | undefined;\n if (envTheme === 'dark' || envTheme === 'light') {\n themeMode = envTheme;\n } else {\n const settings = loadSettings();\n const themePref = settings.preferences.theme;\n if (themePref === 'dark' || themePref === 'light') {\n themeMode = themePref;\n } else {\n const detection = await detectTerminalTheme();\n themeMode = detection.mode;\n detectedBgHex = detection.detectedBgHex;\n }\n }\n applyThemeMode(themeMode, detectedBgHex);\n\n // createMastraCode() brought up shared resources and minted the single\n // session that all work runs through. The AgentController owns no session of its own.\n const session = result.session;\n\n analytics = createMastraCodeAnalytics({ version: getCurrentVersion() });\n analytics.capture('mastracode_session_started', {\n mode: session.mode.get(),\n resourceId: session.identity.getResourceId(),\n hasAuthStorage: Boolean(authStorage),\n hasMcp: Boolean(mcpManager),\n theme: themeMode,\n });\n\n tui = new MastraTUI({\n controller: controller,\n session,\n hookManager,\n analytics,\n authStorage,\n mcpManager,\n pluginManager: result.pluginManager,\n storageMaintenance: result.storageMaintenance,\n processMemoryDiagnostics,\n knowledgeInspector: result.knowledgeInspector,\n appName: 'Mastra Code',\n version: getCurrentVersion(),\n inlineQuestions: true,\n githubSignals: result.githubSignals,\n exit: exitCode => void shutdownAndExit(exitCode),\n ...(pipedInput ? { initialMessage: `The following was piped via stdin:\\n\\n${pipedInput}` } : {}),\n });\n tui.run().catch(error => {\n handleFatalError(error);\n });\n\n if (settings.browser.enabled) {\n void loadBrowser()\n .then(browser => {\n if (!browser) return;\n controller.setBrowser(browser);\n void session.state.set({ activeBrowserSettings: settings.browser } as any).catch(() => {});\n })\n .catch(() => {});\n }\n}\n\nconst asyncCleanup = (): Promise<void> => {\n cleanupPromise ??= (async () => {\n releaseAllThreadLocks();\n // Stop plugin-contributed signal providers (and the plugin reload listener)\n // before quiescing workers: a provider that keeps polling past this point\n // could dispatch into a controller that is shutting down.\n try {\n stopPluginSignalProviders?.();\n } catch {\n // Best-effort — the process is exiting.\n }\n const diagnosticsShutdown = processMemoryDiagnostics\n ? stopProcessMemoryDiagnosticsWithTimeout(processMemoryDiagnostics, message => console.warn(message))\n : undefined;\n const closeSignalsPubSub = (signalsPubSub as { close?: () => Promise<void> | void } | undefined)?.close;\n await Promise.allSettled([mcpManager?.disconnect(), controller?.stopIntervals(), closeSignalsPubSub?.()]);\n // Mastra owns the workspaces and must destroy them to stop retained language\n // servers before storage is closed.\n await Promise.allSettled([controller?.getMastra()?.shutdown(), analytics?.shutdown()]);\n // Checkpoint WAL and close the local storage connection after all producers\n // and timers are quiesced. Idempotent — repeated signals (SIGINT then SIGHUP)\n // close only once. LibSQLStore.close()/LibSQLVector.close() truncate the WAL\n // and switch back to DELETE journal mode for a clean shutdown.\n if (!storageClosed) {\n storageClosed = true;\n await storageMaintenance?.closeStorage?.().catch(() => {\n // Swallow — best-effort cleanup during shutdown. The process is exiting.\n });\n }\n await diagnosticsShutdown;\n })();\n return cleanupPromise;\n};\n\nconst shutdownAndExit = createShutdownCoordinator(asyncCleanup, exitCode => process.exit(exitCode));\n\nprocess.on('beforeExit', () => {\n void asyncCleanup();\n});\nprocess.on('exit', () => {\n // Ensure terminal protocols (kitty keyboard, modifyOtherKeys, bracketed paste,\n // raw mode) are disabled on ANY exit path. Without this, killing the process\n // via SIGINT/SIGTERM leaves the terminal in a corrupted state where keypresses\n // produce escape sequences like \"5;99~\" instead of normal characters.\n try {\n tui?.stop();\n } catch {\n // Failsafe: even if MastraTUI.stop() throws, write raw terminal reset\n // sequences to disable Kitty keyboard protocol, bracketed paste, and\n // modifyOtherKeys. These are the exact sequences pi-tui's terminal.stop()\n // would write.\n }\n // Belt-and-suspenders: always write terminal reset sequences directly,\n // regardless of whether tui.stop() succeeded. Writing them twice is harmless\n // but missing them leaves the terminal in a corrupted state.\n try {\n process.stdout.write(\n '\\x1b[?2004l' + // disable bracketed paste\n '\\x1b[<u' + // pop kitty keyboard protocol\n '\\x1b[>4;0m' + // disable modifyOtherKeys\n '\\x1b[?25h', // show cursor\n );\n if (process.stdin.setRawMode) {\n process.stdin.setRawMode(false);\n }\n } catch {\n // stdout may already be closed during exit\n }\n restoreTerminalForeground();\n releaseAllThreadLocks();\n});\n\n// Start durable diagnostics shutdown before synchronous TUI teardown so a stalled\n// terminal cleanup cannot prevent the final profile capture. The exit handler still\n// provides a failsafe terminal reset if teardown throws.\nconst handleTermSignal = () => {\n void asyncCleanup();\n try {\n tui?.stop();\n } catch {\n // ignored — exit handler has failsafe reset\n }\n void shutdownAndExit(0);\n};\nprocess.on('SIGINT', handleTermSignal);\nprocess.on('SIGTERM', handleTermSignal);\nprocess.on('SIGHUP', handleTermSignal);\n\nfunction hasEconnrefused(err: unknown, depth = 0): boolean {\n if (!err || depth > 5) return false;\n const e = err as any;\n if (e.code === 'ECONNREFUSED') return true;\n if (e.cause) return hasEconnrefused(e.cause, depth + 1);\n // AggregateError has .errors array\n if (Array.isArray(e.errors)) return e.errors.some((inner: unknown) => hasEconnrefused(inner, depth + 1));\n return false;\n}\n\nfunction pluginMain(args: string[]): void {\n if (args[0] !== 'scaffold') {\n process.stderr.write('Usage: mastracode plugin scaffold <dir> [--id acme.foo] [--name \"Foo Tools\"]\\n');\n process.exit(1);\n }\n\n const dir = args[1];\n if (!dir) {\n process.stderr.write('Usage: mastracode plugin scaffold <dir> [--id acme.foo] [--name \"Foo Tools\"]\\n');\n process.exit(1);\n }\n\n const id = readFlag(args, '--id');\n const name = readFlag(args, '--name');\n const targetDir = scaffoldPlugin(dir, { ...(id ? { id } : {}), ...(name ? { name } : {}) });\n process.stdout.write(`${formatScaffoldSuccess(targetDir)}\\n`);\n}\n\nfunction readFlag(args: string[], flag: string): string | undefined {\n const index = args.indexOf(flag);\n if (index === -1) return undefined;\n const value = args[index + 1];\n if (!value || value.startsWith('--')) {\n throw new Error(`Missing value for ${flag}`);\n }\n return value;\n}\n\nfunction handleFatalError(error: unknown): void {\n // Always write to real stderr, even if console.error was overridden\n const write = (msg: string) => process.stderr.write(msg + '\\n');\n\n if (hasEconnrefused(error)) {\n const settings = loadSettings();\n const connStr = settings.storage?.pg?.connectionString;\n const target = connStr ?? 'localhost:5432';\n write(\n `\\nFailed to connect to PostgreSQL at ${target}.` +\n `\\nMake sure the database is running and accessible.` +\n `\\n\\nTo switch back to LibSQL:` +\n `\\n Set MASTRA_STORAGE_BACKEND=libsql or change the backend in /settings\\n`,\n );\n void asyncCleanup();\n try {\n tui?.stop();\n } catch {}\n void shutdownAndExit(1);\n return;\n }\n\n const msg = `Fatal error: ${error instanceof Error ? error.message : String(error)}`;\n write(msg);\n // Write crash log to file so it persists even if terminal closes\n try {\n const crashLog = `[${new Date().toISOString()}] ${msg}\\n${error instanceof Error && error.stack ? error.stack + '\\n' : ''}`;\n fs.appendFileSync('/tmp/mastra-crash.log', crashLog);\n } catch {}\n if (error instanceof Error && error.stack) {\n write(error.stack);\n }\n void asyncCleanup();\n try {\n tui?.stop();\n } catch {}\n void shutdownAndExit(1);\n}\n\nasync function main() {\n if (process.argv[2] === 'plugin') {\n return pluginMain(process.argv.slice(3));\n }\n\n if (hasHeadlessFlag(process.argv) || process.argv.includes('--help') || process.argv.includes('-h')) {\n return runMCCli();\n }\n\n if (process.argv.includes('--acp')) {\n const { acpMain } = await import('@mastra/code-sdk/acp/index');\n return acpMain({ dangerousAutoApprove: process.argv.includes('--dangerous-auto-approve') });\n }\n\n // When stdin is piped (e.g. `cat foo | mastracode`), drain the pipe fully\n // before starting the TUI. The drain blocks until the sender process exits\n // and closes its stdout, so we never see partial output.\n let pipedInput: string | null = null;\n if (!process.stdin.isTTY) {\n process.stderr.write('Reading piped input...\\n');\n pipedInput = await drainPipedStdin();\n\n // Always reopen a real TTY — even if the pipe was empty, the original\n // stdin is consumed/closed and the TUI needs a live TTY for keyboard input.\n const reopenedStdin = reopenStdinFromTTY();\n if (!reopenedStdin) {\n process.stderr.write('No TTY available — falling back to headless mode.\\n');\n return runMCCli(pipedInput);\n }\n }\n\n return tuiMain(pipedInput);\n}\n\nmain().catch(error => {\n handleFatalError(error);\n});\n"],"mappings":";;;;;;;;;;;;;;;AAQA,eAAsB,iCACpB,KACA,MACA,cAEqCA,4CAAAA,+CACF;CACnC,QAAA,GAAA,4CAAA,wCAAA,CAA+C,YAAY,GAAG,GAAG,IAAI;AACvE;AAEA,SAAgB,0BACd,SACA,MACA,YAAY,KACyB;CACrC,IAAI,kBAAwC;CAC5C,QAAO,aAAY;EACjB,qBAAqB,YAAY;GAC/B,IAAI;GACJ,MAAM,QAAQ,KAAK,CACjB,QAAQ,CAAC,CAAC,YAAY,KAAA,CAAS,GAC/B,IAAI,SAAc,YAAW;IAC3B,UAAU,WAAW,SAAS,SAAS;GACzC,CAAC,CACH,CAAC;GACD,IAAI,SAAS,aAAa,OAAO;GACjC,KAAK,QAAQ;EACf,EAAA,CAAG;EACH,OAAO;CACT;AACF;;;AClCA,SAAgB,oBAA4B;CAExC,OAAA;AAKJ;;;;;;ACcA,IAAI;AACJ,IAAI;AACJ,IAAI;AACJ,IAAI;AACJ,IAAI;AACJ,IAAI;AACJ,IAAI;AACJ,IAAI;AACJ,IAAI;AACJ,IAAI;AACJ,IAAI,gBAAgB;AACpB,IAAI,iBAAuC;AAE3C,SAAS,YAAY,MAAuB;CAC1C,OAAO;EAAC;EAAK;EAAQ;EAAO;CAAI,CAAC,CAAC,SAAS,QAAQ,IAAI,KAAK,EAAE,KAAK,CAAC,CAAC,YAAY,KAAK,EAAE;AAC1F;AAEA,SAAS,6BAA6B;CACpC,MAAM,iBAAiB,QAAQ,IAAI,qBAAqB,KAAK;CAC7D,MAAM,eAAwC,CAAC;CAC/C,IAAI,gBAAgB,aAAa,iBAAiB;CAClD,IAAI,YAAY,iBAAiB,GAAG,aAAa,OAAO;CACxD,OAAO,OAAO,KAAK,YAAY,CAAC,CAAC,SAAS,IAAI,eAAe,KAAA;AAC/D;AAGA,QAAQ,GAAG,sBAAqB,UAAS;CAGvC,KAAA,GAAA,sCAAA,uBAAA,CAA2B,KAAK,GAAG;CACnC,iBAAiB,KAAK;AACxB,CAAC;AACD,QAAQ,GAAG,uBAAsB,WAAU;CACzC,KAAA,GAAA,sCAAA,uBAAA,CAA2B,MAAM,GAAG;CACpC,iBAAiB,kBAAkB,QAAQ,SAAS,IAAI,MAAM,OAAO,MAAM,CAAC,CAAC;AAC/E,CAAC;AAED,eAAe,QAAQ,YAA4B;CACjD,MAAM,YAAA,GAAA,qCAAA,aAAA,CAAwB;CAC9B,2BAA2B,MAAM,iCAAiC,QAAQ,MAAK,YAAW;EACxF,QAAQ,KAAK,KAAK,SAAS;CAC7B,CAAC;CACD,IAAI;CACJ,MAAM,oBAAoB;EACxB,oBAAA,GAAA,qCAAA,0BAAA,CAA6C,SAAS,OAAO;EAC7D,OAAO;CACT;CAEA,MAAM,eAAe,2BAA2B;CAChD,MAAM,SAAS,OAAA,GAAA,iBAAA,iBAAA,CAAuB;EACpC,kBAAkB,CAAC,YAAY,uCAAuC;EACtE,YAAY,YAAY,wBAAwB;EAChD,cAAc,YAAY,0BAA0B;EACpD,GAAI,YAAY,2BAA2B,IAAI,EAAE,QAAQ,MAAe,IAAI,CAAC;EAC7E,GAAI,eAAe,EAAgB,aAAsB,IAAI,CAAC;CAChE,CAAC;CACD,aAAa,OAAO;CACpB,aAAa,OAAO;CACpB,cAAc,OAAO;CACrB,cAAc,OAAO;CACrB,gBAAgB,OAAO;CACvB,qBAAqB,OAAO;CAC5B,4BAA4B,OAAO;CAEnC,IAAI,OAAO,gBACT,QAAQ,KAAK,KAAK,OAAO,gBAAgB;CAE3C,IAAI,OAAO,sBACT,QAAQ,KAAK,KAAK,OAAO,sBAAsB;CAOjD,CAAA,GAAA,iCAAA,kBAAA,CAAkB;CAIlB,MAAM,WAAW,QAAQ,IAAI,cAAc,YAAY;CACvD,IAAI;CACJ,IAAI;CACJ,IAAI,aAAa,UAAU,aAAa,SACtC,YAAY;MACP;EAEL,MAAM,aAAA,GAAA,qCAAA,aAAA,CAAmB,CAAC,CAAC,YAAY;EACvC,IAAI,cAAc,UAAU,cAAc,SACxC,YAAY;OACP;GACL,MAAM,YAAY,MAAMC,YAAAA,oBAAoB;GAC5C,YAAY,UAAU;GACtB,gBAAgB,UAAU;EAC5B;CACF;CACA,YAAA,eAAe,WAAW,aAAa;CAIvC,MAAM,UAAU,OAAO;CAEvB,aAAA,GAAA,2BAAA,0BAAA,CAAsC,EAAE,SAAS,kBAAkB,EAAE,CAAC;CACtE,UAAU,QAAQ,8BAA8B;EAC9C,MAAM,QAAQ,KAAK,IAAI;EACvB,YAAY,QAAQ,SAAS,cAAc;EAC3C,gBAAgB,QAAQ,WAAW;EACnC,QAAQ,QAAQ,UAAU;EAC1B,OAAO;CACT,CAAC;CAED,MAAM,IAAIC,YAAAA,UAAU;EACN;EACZ;EACA;EACA;EACA;EACA;EACA,eAAe,OAAO;EACtB,oBAAoB,OAAO;EAC3B;EACA,oBAAoB,OAAO;EAC3B,SAAS;EACT,SAAS,kBAAkB;EAC3B,iBAAiB;EACjB,eAAe,OAAO;EACtB,OAAM,aAAY,KAAK,gBAAgB,QAAQ;EAC/C,GAAI,aAAa,EAAE,gBAAgB,yCAAyC,aAAa,IAAI,CAAC;CAChG,CAAC;CACD,IAAI,IAAI,CAAC,CAAC,OAAM,UAAS;EACvB,iBAAiB,KAAK;CACxB,CAAC;CAED,IAAI,SAAS,QAAQ,SACnB,YAAiB,CAAC,CACf,MAAK,YAAW;EACf,IAAI,CAAC,SAAS;EACd,WAAW,WAAW,OAAO;EAC7B,QAAa,MAAM,IAAI,EAAE,uBAAuB,SAAS,QAAQ,CAAQ,CAAC,CAAC,YAAY,CAAC,CAAC;CAC3F,CAAC,CAAC,CACD,YAAY,CAAC,CAAC;AAErB;AAEA,MAAM,qBAAoC;CACxC,oBAAoB,YAAY;EAC9B,CAAA,GAAA,mCAAA,sBAAA,CAAsB;EAItB,IAAI;GACF,4BAA4B;EAC9B,QAAQ,CAER;EACA,MAAM,sBAAsB,4BAAA,GAAA,4CAAA,wCAAA,CACgB,2BAA0B,YAAW,QAAQ,KAAK,OAAO,CAAC,IAClG,KAAA;EACJ,MAAM,qBAAsB,eAAsE;EAClG,MAAM,QAAQ,WAAW;GAAC,YAAY,WAAW;GAAG,YAAY,cAAc;GAAG,qBAAqB;EAAC,CAAC;EAGxG,MAAM,QAAQ,WAAW,CAAC,YAAY,UAAU,CAAC,EAAE,SAAS,GAAG,WAAW,SAAS,CAAC,CAAC;EAKrF,IAAI,CAAC,eAAe;GAClB,gBAAgB;GAChB,MAAM,oBAAoB,eAAe,CAAC,CAAC,YAAY,CAEvD,CAAC;EACH;EACA,MAAM;CACR,EAAA,CAAG;CACH,OAAO;AACT;AAEA,MAAM,kBAAkB,0BAA0B,eAAc,aAAY,QAAQ,KAAK,QAAQ,CAAC;AAElG,QAAQ,GAAG,oBAAoB;CAC7B,aAAkB;AACpB,CAAC;AACD,QAAQ,GAAG,cAAc;CAKvB,IAAI;EACF,KAAK,KAAK;CACZ,QAAQ,CAKR;CAIA,IAAI;EACF,QAAQ,OAAO,MACb,uCAIF;EACA,IAAI,QAAQ,MAAM,YAChB,QAAQ,MAAM,WAAW,KAAK;CAElC,QAAQ,CAER;CACA,YAAA,0BAA0B;CAC1B,CAAA,GAAA,mCAAA,sBAAA,CAAsB;AACxB,CAAC;AAKD,MAAM,yBAAyB;CAC7B,aAAkB;CAClB,IAAI;EACF,KAAK,KAAK;CACZ,QAAQ,CAER;CACA,gBAAqB,CAAC;AACxB;AACA,QAAQ,GAAG,UAAU,gBAAgB;AACrC,QAAQ,GAAG,WAAW,gBAAgB;AACtC,QAAQ,GAAG,UAAU,gBAAgB;AAErC,SAAS,gBAAgB,KAAc,QAAQ,GAAY;CACzD,IAAI,CAAC,OAAO,QAAQ,GAAG,OAAO;CAC9B,MAAM,IAAI;CACV,IAAI,EAAE,SAAS,gBAAgB,OAAO;CACtC,IAAI,EAAE,OAAO,OAAO,gBAAgB,EAAE,OAAO,QAAQ,CAAC;CAEtD,IAAI,MAAM,QAAQ,EAAE,MAAM,GAAG,OAAO,EAAE,OAAO,MAAM,UAAmB,gBAAgB,OAAO,QAAQ,CAAC,CAAC;CACvG,OAAO;AACT;AAEA,SAAS,WAAW,MAAsB;CACxC,IAAI,KAAK,OAAO,YAAY;EAC1B,QAAQ,OAAO,MAAM,kFAAgF;EACrG,QAAQ,KAAK,CAAC;CAChB;CAEA,MAAM,MAAM,KAAK;CACjB,IAAI,CAAC,KAAK;EACR,QAAQ,OAAO,MAAM,kFAAgF;EACrG,QAAQ,KAAK,CAAC;CAChB;CAEA,MAAM,KAAK,SAAS,MAAM,MAAM;CAChC,MAAM,OAAO,SAAS,MAAM,QAAQ;CACpC,MAAM,aAAA,GAAA,kCAAA,eAAA,CAA2B,KAAK;EAAE,GAAI,KAAK,EAAE,GAAG,IAAI,CAAC;EAAI,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;CAAG,CAAC;CAC1F,QAAQ,OAAO,MAAM,IAAA,GAAA,kCAAA,sBAAA,CAAyB,SAAS,EAAE,GAAG;AAC9D;AAEA,SAAS,SAAS,MAAgB,MAAkC;CAClE,MAAM,QAAQ,KAAK,QAAQ,IAAI;CAC/B,IAAI,UAAU,IAAI,OAAO,KAAA;CACzB,MAAM,QAAQ,KAAK,QAAQ;CAC3B,IAAI,CAAC,SAAS,MAAM,WAAW,IAAI,GACjC,MAAM,IAAI,MAAM,qBAAqB,MAAM;CAE7C,OAAO;AACT;AAEA,SAAS,iBAAiB,OAAsB;CAE9C,MAAM,SAAS,QAAgB,QAAQ,OAAO,MAAM,MAAM,IAAI;CAE9D,IAAI,gBAAgB,KAAK,GAAG;EAI1B,MACE,yCAAA,GAAA,qCAAA,aAAA,CAHqB,CAAC,CAAC,SAAS,IAAI,oBACZ,iBAEuB,4JAIjD;EACA,aAAkB;EAClB,IAAI;GACF,KAAK,KAAK;EACZ,QAAQ,CAAC;EACT,gBAAqB,CAAC;EACtB;CACF;CAEA,MAAM,MAAM,gBAAgB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;CACjF,MAAM,GAAG;CAET,IAAI;EACF,MAAM,WAAW,qBAAI,IAAI,KAAK,EAAA,CAAE,YAAY,EAAE,IAAI,IAAI,IAAI,iBAAiB,SAAS,MAAM,QAAQ,MAAM,QAAQ,OAAO;EACvH,GAAA,QAAG,eAAe,yBAAyB,QAAQ;CACrD,QAAQ,CAAC;CACT,IAAI,iBAAiB,SAAS,MAAM,OAClC,MAAM,MAAM,KAAK;CAEnB,aAAkB;CAClB,IAAI;EACF,KAAK,KAAK;CACZ,QAAQ,CAAC;CACT,gBAAqB,CAAC;AACxB;AAEA,eAAe,OAAO;CACpB,IAAI,QAAQ,KAAK,OAAO,UACtB,OAAO,WAAW,QAAQ,KAAK,MAAM,CAAC,CAAC;CAGzC,KAAA,GAAA,gCAAA,gBAAA,CAAoB,QAAQ,IAAI,KAAK,QAAQ,KAAK,SAAS,QAAQ,KAAK,QAAQ,KAAK,SAAS,IAAI,GAChG,QAAA,GAAA,gCAAA,SAAA,CAAgB;CAGlB,IAAI,QAAQ,KAAK,SAAS,OAAO,GAAG;EAClC,MAAM,EAAE,YAAY,MAAM,OAAO;EACjC,OAAO,QAAQ,EAAE,sBAAsB,QAAQ,KAAK,SAAS,0BAA0B,EAAE,CAAC;CAC5F;CAKA,IAAI,aAA4B;CAChC,IAAI,CAAC,QAAQ,MAAM,OAAO;EACxB,QAAQ,OAAO,MAAM,0BAA0B;EAC/C,aAAa,OAAA,GAAA,kCAAA,gBAAA,CAAsB;EAKnC,IAAI,EAAA,GAAA,kCAAA,mBAAA,CAAa,GAAG;GAClB,QAAQ,OAAO,MAAM,qDAAqD;GAC1E,QAAA,GAAA,gCAAA,SAAA,CAAgB,UAAU;EAC5B;CACF;CAEA,OAAO,QAAQ,UAAU;AAC3B;AAEA,KAAK,CAAC,CAAC,OAAM,UAAS;CACpB,iBAAiB,KAAK;AACxB,CAAC"}
|
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { d as detectTerminalTheme, f as applyThemeMode, t as MastraTUI, v as restoreTerminalForeground } from "./tui-
|
|
2
|
+
import { d as detectTerminalTheme, f as applyThemeMode, t as MastraTUI, v as restoreTerminalForeground } from "./tui-Cdxsbuqs.js";
|
|
3
3
|
import { createMastraCode } from "@mastra/code-sdk";
|
|
4
4
|
import fs from "fs";
|
|
5
5
|
import { createMastraCodeAnalytics } from "@mastra/code-sdk/analytics";
|
|
@@ -7,12 +7,32 @@ import { isStreamDestroyedError } from "@mastra/code-sdk/error-classification";
|
|
|
7
7
|
import { hasHeadlessFlag, runMCCli } from "@mastra/code-sdk/headless/index";
|
|
8
8
|
import { createBrowserFromSettings, loadSettings } from "@mastra/code-sdk/onboarding/settings";
|
|
9
9
|
import { formatScaffoldSuccess, scaffoldPlugin } from "@mastra/code-sdk/plugins/scaffold";
|
|
10
|
+
import { createProcessMemoryDiagnosticsFromEnvironment, startConfiguredProcessMemoryDiagnostics, stopProcessMemoryDiagnosticsWithTimeout } from "@mastra/code-sdk/process-memory-diagnostics";
|
|
10
11
|
import { setupDebugLogging } from "@mastra/code-sdk/utils/debug-log";
|
|
11
12
|
import { drainPipedStdin, reopenStdinFromTTY } from "@mastra/code-sdk/utils/stdin-pipe";
|
|
12
13
|
import { releaseAllThreadLocks } from "@mastra/code-sdk/utils/thread-lock";
|
|
14
|
+
//#region src/process-memory-diagnostics-lifecycle.ts
|
|
15
|
+
async function startTuiProcessMemoryDiagnostics(env, warn, createSetup = createProcessMemoryDiagnosticsFromEnvironment) {
|
|
16
|
+
return startConfiguredProcessMemoryDiagnostics(createSetup(env), warn);
|
|
17
|
+
}
|
|
18
|
+
function createShutdownCoordinator(cleanup, exit, timeoutMs = 5e3) {
|
|
19
|
+
let shutdownPromise = null;
|
|
20
|
+
return (exitCode) => {
|
|
21
|
+
shutdownPromise ??= (async () => {
|
|
22
|
+
let timeout;
|
|
23
|
+
await Promise.race([cleanup().catch(() => void 0), new Promise((resolve) => {
|
|
24
|
+
timeout = setTimeout(resolve, timeoutMs);
|
|
25
|
+
})]);
|
|
26
|
+
if (timeout) clearTimeout(timeout);
|
|
27
|
+
exit(exitCode);
|
|
28
|
+
})();
|
|
29
|
+
return shutdownPromise;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
13
33
|
//#region src/version.ts
|
|
14
34
|
function getCurrentVersion() {
|
|
15
|
-
return "0.
|
|
35
|
+
return "0.35.0-alpha.1";
|
|
16
36
|
}
|
|
17
37
|
//#endregion
|
|
18
38
|
//#region src/main.ts
|
|
@@ -28,7 +48,9 @@ let storageMaintenance;
|
|
|
28
48
|
let stopPluginSignalProviders;
|
|
29
49
|
let analytics;
|
|
30
50
|
let tui;
|
|
51
|
+
let processMemoryDiagnostics;
|
|
31
52
|
let storageClosed = false;
|
|
53
|
+
let cleanupPromise = null;
|
|
32
54
|
function isTruthyEnv(name) {
|
|
33
55
|
return [
|
|
34
56
|
"1",
|
|
@@ -54,6 +76,9 @@ process.on("unhandledRejection", (reason) => {
|
|
|
54
76
|
});
|
|
55
77
|
async function tuiMain(pipedInput) {
|
|
56
78
|
const settings = loadSettings();
|
|
79
|
+
processMemoryDiagnostics = await startTuiProcessMemoryDiagnostics(process.env, (warning) => {
|
|
80
|
+
console.info(`⚠ ${warning}`);
|
|
81
|
+
});
|
|
57
82
|
let browserPromise;
|
|
58
83
|
const loadBrowser = () => {
|
|
59
84
|
browserPromise ??= createBrowserFromSettings(settings.browser);
|
|
@@ -109,11 +134,13 @@ async function tuiMain(pipedInput) {
|
|
|
109
134
|
mcpManager,
|
|
110
135
|
pluginManager: result.pluginManager,
|
|
111
136
|
storageMaintenance: result.storageMaintenance,
|
|
137
|
+
processMemoryDiagnostics,
|
|
112
138
|
knowledgeInspector: result.knowledgeInspector,
|
|
113
139
|
appName: "Mastra Code",
|
|
114
140
|
version: getCurrentVersion(),
|
|
115
141
|
inlineQuestions: true,
|
|
116
142
|
githubSignals: result.githubSignals,
|
|
143
|
+
exit: (exitCode) => void shutdownAndExit(exitCode),
|
|
117
144
|
...pipedInput ? { initialMessage: `The following was piped via stdin:\n\n${pipedInput}` } : {}
|
|
118
145
|
});
|
|
119
146
|
tui.run().catch((error) => {
|
|
@@ -125,23 +152,29 @@ async function tuiMain(pipedInput) {
|
|
|
125
152
|
session.state.set({ activeBrowserSettings: settings.browser }).catch(() => {});
|
|
126
153
|
}).catch(() => {});
|
|
127
154
|
}
|
|
128
|
-
const asyncCleanup =
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
155
|
+
const asyncCleanup = () => {
|
|
156
|
+
cleanupPromise ??= (async () => {
|
|
157
|
+
releaseAllThreadLocks();
|
|
158
|
+
try {
|
|
159
|
+
stopPluginSignalProviders?.();
|
|
160
|
+
} catch {}
|
|
161
|
+
const diagnosticsShutdown = processMemoryDiagnostics ? stopProcessMemoryDiagnosticsWithTimeout(processMemoryDiagnostics, (message) => console.warn(message)) : void 0;
|
|
162
|
+
const closeSignalsPubSub = signalsPubSub?.close;
|
|
163
|
+
await Promise.allSettled([
|
|
164
|
+
mcpManager?.disconnect(),
|
|
165
|
+
controller?.stopIntervals(),
|
|
166
|
+
closeSignalsPubSub?.()
|
|
167
|
+
]);
|
|
168
|
+
await Promise.allSettled([controller?.getMastra()?.shutdown(), analytics?.shutdown()]);
|
|
169
|
+
if (!storageClosed) {
|
|
170
|
+
storageClosed = true;
|
|
171
|
+
await storageMaintenance?.closeStorage?.().catch(() => {});
|
|
172
|
+
}
|
|
173
|
+
await diagnosticsShutdown;
|
|
174
|
+
})();
|
|
175
|
+
return cleanupPromise;
|
|
144
176
|
};
|
|
177
|
+
const shutdownAndExit = createShutdownCoordinator(asyncCleanup, (exitCode) => process.exit(exitCode));
|
|
145
178
|
process.on("beforeExit", () => {
|
|
146
179
|
asyncCleanup();
|
|
147
180
|
});
|
|
@@ -157,10 +190,11 @@ process.on("exit", () => {
|
|
|
157
190
|
releaseAllThreadLocks();
|
|
158
191
|
});
|
|
159
192
|
const handleTermSignal = () => {
|
|
193
|
+
asyncCleanup();
|
|
160
194
|
try {
|
|
161
195
|
tui?.stop();
|
|
162
196
|
} catch {}
|
|
163
|
-
|
|
197
|
+
shutdownAndExit(0);
|
|
164
198
|
};
|
|
165
199
|
process.on("SIGINT", handleTermSignal);
|
|
166
200
|
process.on("SIGTERM", handleTermSignal);
|
|
@@ -202,7 +236,12 @@ function handleFatalError(error) {
|
|
|
202
236
|
const write = (msg) => process.stderr.write(msg + "\n");
|
|
203
237
|
if (hasEconnrefused(error)) {
|
|
204
238
|
write(`\nFailed to connect to PostgreSQL at ${loadSettings().storage?.pg?.connectionString ?? "localhost:5432"}.\nMake sure the database is running and accessible.\n\nTo switch back to LibSQL:\n Set MASTRA_STORAGE_BACKEND=libsql or change the backend in /settings\n`);
|
|
205
|
-
|
|
239
|
+
asyncCleanup();
|
|
240
|
+
try {
|
|
241
|
+
tui?.stop();
|
|
242
|
+
} catch {}
|
|
243
|
+
shutdownAndExit(1);
|
|
244
|
+
return;
|
|
206
245
|
}
|
|
207
246
|
const msg = `Fatal error: ${error instanceof Error ? error.message : String(error)}`;
|
|
208
247
|
write(msg);
|
|
@@ -211,7 +250,11 @@ function handleFatalError(error) {
|
|
|
211
250
|
fs.appendFileSync("/tmp/mastra-crash.log", crashLog);
|
|
212
251
|
} catch {}
|
|
213
252
|
if (error instanceof Error && error.stack) write(error.stack);
|
|
214
|
-
|
|
253
|
+
asyncCleanup();
|
|
254
|
+
try {
|
|
255
|
+
tui?.stop();
|
|
256
|
+
} catch {}
|
|
257
|
+
shutdownAndExit(1);
|
|
215
258
|
}
|
|
216
259
|
async function main() {
|
|
217
260
|
if (process.argv[2] === "plugin") return pluginMain(process.argv.slice(3));
|