Skip to content

Commit dbb2d3b

Browse files
cameroncookecodex
andauthored
feat(log-capture): Durable OSLog session tracking and executor settlement fixes (#336)
* fix(snapshot-tests): Align MCP and CLI transcript fixtures Route shared xcodebuild snapshot scenarios through canonical CLI fixtures and make MCP durable text rendering use the same non-interactive transcript formatter. This removes MCP-specific newline drift and keeps test discovery formatting consistent across success and failure paths. Also surface selective test targeting in test headers and limit discovery previews to the first six tests so the canonical fixtures stay readable while preserving parity across runtimes. Co-Authored-By: OpenAI Codex <noreply@openai.com> * fix(command): Settle executor on exit+streams-drained instead of close alone The close event can be delayed indefinitely when a detached grandchild inherits stdout/stderr file descriptors. Replace the single close listener with a state machine that tracks open streams, observes exit, and settles when both conditions are met. A 100ms safety timer after exit handles the case where streams never drain. The close event remains a final authority that forces immediate settlement. * fix(test-common): Finalize xcodebuild pipeline on post-startup exceptions When the executor throws after startBuildPipeline has been called, the pipeline response was left in a pending state with no output. Hoist the started variable above the try block so the catch handler can call finalizeInlineXcodebuild and produce a proper error response with build log links. * feat(log-capture): Add durable OSLog session tracking with cross-process registry Detached simctl log stream helper processes were spawned fire-and-forget with no tracking, accumulating silently across server restarts. Add a filesystem-backed registry under ~/Library/Developer/XcodeBuildMCP/state/ that records each helper's PID, owner instance, and expected command signature. Liveness is verified via ps command matching to handle PID recycling. On app launch, existing sessions for the same simulator+bundleId are cleaned up before spawning a new helper. On app stop, tracked sessions are terminated alongside the simctl terminate call. On server shutdown, only sessions owned by the current process are stopped. The lifecycle snapshot and session status resource expose tracked session counts for observability. * fix(simulator): Persist launch-owned OSLog sessions Track simulator launch OSLog helpers in a durable registry so stop and shutdown can clean them up across independent CLI and MCP process lifetimes. Keep lifecycle visibility accurate for parallel runs, prune stale or corrupt registry entries, and tighten the related command and rendering refactors that support the new ownership model. Refs GH-273 Co-Authored-By: OpenAI Codex <noreply@openai.com> * ref(simulator): Harden OSLog session tracking Batch registry PID sampling so durable OSLog cleanup does less process churn while keeping stale-entry pruning behavior unchanged. Make the test-only session reset helper explicit, guard simulator device parsing against malformed simctl payloads, and avoid duplicate local cleanup when both child exit and close fire. These changes keep the durable registry design the same while tightening a few rough edges called out in follow-up review. Co-Authored-By: OpenAI Codex <noreply@openai.com> * fix(renderer,test-execution): Correct next-step runtime syntax and resultBundlePath routing The CLI text renderer always emitted next-step suggestions in CLI syntax regardless of the event's runtime field. Now MCP/daemon runtimes get MCP tool-call syntax while CLI keeps CLI syntax. The simulator two-phase execution plan passed -resultBundlePath to both build-for-testing and test-without-building. This flag only belongs on the test-without-building invocation; passing it to both caused xcodebuild conflicts. Extract it from extraArgs and route it to the test phase only. * ref(snapshot-tests): Invoke CLI subprocess uniformly and expand MCP fixture coverage Replace direct module imports in the snapshot harness with CLI subprocess invocations so every test exercises the real transport path. The resource harness now connects via MCP SDK client instead of importing handler modules directly. - Remove invokeDirect path and shutdownAllSimulatorsExcept - Add createTemporarySimulator/deleteSimulator/shutdownSimulator helpers - Add output-parsers for extracting app paths, PIDs, simulator entries - Resource harness uses StdioClientTransport + MCP Client - Add normalizers for MCP process IDs and OSLog session arrays - Remove CLI session-management fixtures (MCP-only tools) - Add missing MCP fixtures for device, macos, simulator, swift-package - Update all suites to use CLI-based harness patterns --------- Co-authored-by: OpenAI Codex <noreply@openai.com>
1 parent 713a2dc commit dbb2d3b

File tree

350 files changed

+8296
-3235
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

350 files changed

+8296
-3235
lines changed
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
# Investigation: Simulator test hang and EMFILE failures
2+
3+
## Summary
4+
XcodeBuildMCP definitively leaks detached simulator OSLog stream processes from the simulator launch-with-logging path. Real-world verification showed that production code created orphaned `simctl spawn <sim> log stream ...` processes under PID 1, the normal `simulator stop` command did not clean them up, and repeated launches accumulated additional survivors. After clearing the leaked processes, the previously unhealthy simulator recovered: `xcrun simctl get_app_container ...` completed successfully in `259 ms`, and a real `node build/cli.js simulator test ...` run progressed through `test-without-building`, executed tests, and returned control to the terminal instead of hanging at `Process spawn via launchd failed`. That makes the leak the confirmed cause of the broken simulator state behind the original symptom.
5+
6+
## Symptoms
7+
- `build-for-testing` succeeds.
8+
- `test-without-building` reports `Process spawn via launchd failed` and `Too many open files`.
9+
- `NSPOSIXErrorDomain Code 24` appears in Xcode output.
10+
- The failing `xcodebuild` process can remain alive after printing the error.
11+
- On the machine, dozens of orphaned `simctl spawn ... log stream ...` processes existed for the same simulator and bundle.
12+
13+
## Investigation Log
14+
15+
### Phase 1 - Initial machine assessment
16+
**Hypothesis:** The simulator/Xcode environment had accumulated leaked processes or descriptors from earlier E2E/manual work.
17+
**Findings:** The shell limit was high, but launchd soft maxfiles was low, and the machine had many orphaned simulator log-stream processes plus multiple stuck `xcodebuild` instances.
18+
**Evidence:**
19+
- `ulimit -n` returned `1048575`.
20+
- `launchctl limit maxfiles` returned soft `256`, hard `unlimited`.
21+
- `ps` showed **81** live `simctl spawn 01DA97D9-3856-46C5-A75E-DDD48100B2DB log stream --level=debug --predicate subsystem == "io.sentry.calculatorapp"` processes under PID 1.
22+
- `ps -p 46498,48422 -o pid,ppid,stat,etime,command` showed two stuck `xcodebuild ... test-without-building` processes still alive.
23+
- `lsof -p 46498 | wc -l` and `lsof -p 48422 | wc -l` each showed about 200 open fds.
24+
**Conclusion:** Confirmed degraded local environment. Needed to separate product leak from broader simulator/Xcode damage.
25+
26+
### Phase 2 - Code path identification
27+
**Hypothesis:** Recent simulator launch work in XcodeBuildMCP explicitly creates detached OSLog stream processes and fails to manage their lifecycle.
28+
**Findings:** `launchSimulatorAppWithLogging()` starts an OSLog stream via `startOsLogStream()`. That helper spawns detached `xcrun simctl spawn ... log stream` children and immediately `unref()`s them. `stop_app_sim` only terminates the app and does not stop the OSLog stream. Session tracking only accounts for `activeLogSessions` from `log_capture.ts`, not these detached children.
29+
**Evidence:**
30+
- `src/utils/simulator-steps.ts:205` calls `startOsLogStream(...)`.
31+
- `src/utils/simulator-steps.ts:251` defines `startOsLogStream`.
32+
- `src/utils/simulator-steps.ts:278` sets `detached: true`.
33+
- `src/utils/simulator-steps.ts:281` calls `child.unref()`.
34+
- `src/mcp/tools/simulator/stop_app_sim.ts:58` only runs `['xcrun', 'simctl', 'terminate', simulatorId, params.bundleId]`.
35+
- `src/utils/log_capture.ts:60` stores tracked sessions in `activeLogSessions`.
36+
- `src/utils/log-capture/index.ts:10-11` lists only `activeLogSessions` ids.
37+
- `src/utils/session-status.ts:52` reports simulator active session ids from `listActiveSimulatorLogSessionIds()`.
38+
**Conclusion:** Confirmed product design bug: detached OSLog children are created outside the tracked log-session lifecycle.
39+
40+
### Phase 3 - Real-world proof that production code creates orphaned OSLog children
41+
**Hypothesis:** The production simulator launch helper is capable of creating the exact orphaned `simctl spawn ... log stream ...` processes observed on the machine.
42+
**Findings:** After clearing all existing matching orphan processes, running the production `launchSimulatorAppWithLogging()` helper created a new detached `simctl spawn ... log stream ...` process under PID 1 for the exact simulator and bundle under investigation.
43+
**Evidence:**
44+
- Before the controlled run, matching process count was `0`.
45+
- Production helper invocation used built code:
46+
```sh
47+
node --input-type=module - <<'NODE'
48+
import { launchSimulatorAppWithLogging } from './build/utils/simulator-steps.js';
49+
const fakeExecutor = async () => ({ success: true, output: 'io.sentry.calculatorapp: 123', process: { pid: 123 }, exitCode: 0 });
50+
const result = await launchSimulatorAppWithLogging(
51+
'01DA97D9-3856-46C5-A75E-DDD48100B2DB',
52+
'io.sentry.calculatorapp',
53+
fakeExecutor,
54+
);
55+
console.log(JSON.stringify(result, null, 2));
56+
NODE
57+
```
58+
- That helper returned success and produced an OSLog file:
59+
`/Users/cameroncooke/Library/Developer/XcodeBuildMCP/logs/io.sentry.calculatorapp_oslog_2026-04-11T08-46-40-929Z_pid62912.log`
60+
- Immediately afterward, process table showed:
61+
`62966 1 00:11 /Library/Developer/PrivateFrameworks/CoreSimulator.framework/Versions/A/Resources/bin/simctl spawn 01DA97D9-3856-46C5-A75E-DDD48100B2DB log stream --level=debug --predicate subsystem == "io.sentry.calculatorapp"`
62+
- The OSLog file contained runtime output from the launched app, including:
63+
`Calculator app launched`
64+
**Conclusion:** Definitively confirmed. The observed orphan command line is created by XcodeBuildMCP production code.
65+
66+
### Phase 4 - Real-world proof that normal stop does not clean up the leaked child
67+
**Hypothesis:** The normal stop tool leaves the detached OSLog stream running.
68+
**Findings:** Running the normal stop command successfully terminated the app, but the detached log-stream process remained alive under PID 1.
69+
**Evidence:**
70+
- Stop command used:
71+
```sh
72+
node build/cli.js simulator stop --simulator-id 01DA97D9-3856-46C5-A75E-DDD48100B2DB --bundle-id io.sentry.calculatorapp --output text
73+
```
74+
- CLI output reported `App stopped successfully`.
75+
- After stop, process table still showed:
76+
`62966 1 00:20 /Library/Developer/PrivateFrameworks/CoreSimulator.framework/Versions/A/Resources/bin/simctl spawn 01DA97D9-3856-46C5-A75E-DDD48100B2DB log stream --level=debug --predicate subsystem == "io.sentry.calculatorapp"`
77+
- Matching process count remained `1`.
78+
**Conclusion:** Definitively confirmed. `simulator stop` does not stop the detached OSLog stream child created by launch-with-logging.
79+
80+
### Phase 5 - Real-world proof of accumulation
81+
**Hypothesis:** Repeated launches can accumulate additional detached OSLog stream survivors.
82+
**Findings:** A second invocation of the same production helper created another survivor. Two distinct PIDs were alive concurrently under PID 1.
83+
**Evidence:**
84+
- Second production helper invocation returned success and wrote a second OSLog file:
85+
`/Users/cameroncooke/Library/Developer/XcodeBuildMCP/logs/io.sentry.calculatorapp_oslog_2026-04-11T08-47-12-997Z_pid63093.log`
86+
- Process table then showed both:
87+
- `62966 1 00:49 /Library/Developer/PrivateFrameworks/CoreSimulator.framework/Versions/A/Resources/bin/simctl spawn ...`
88+
- `63142 1 00:17 /Library/Developer/PrivateFrameworks/CoreSimulator.framework/Versions/A/Resources/bin/simctl spawn ...`
89+
- Matching process count was `2`.
90+
- The first OSLog file later contained output from both launches, while the second file also contained output from the second launch, showing overlapping capture behavior.
91+
**Conclusion:** Definitively confirmed. The leak accumulates across repeated launches.
92+
93+
### Phase 6 - Short-timeout false positive and post-cleanup recovery
94+
**Hypothesis:** The earlier `get_app_container` timeout may have been a measurement artifact, and the real question is whether the simulator recovers once the leaked processes are removed.
95+
**Findings:** The earlier 5-second probe was too aggressive and not a reliable signal. After cleanup, rerunning the simulator metadata command with a realistic timeout completed successfully in `259 ms`. A real `simulator test` run then progressed through `build-for-testing`, entered `test-without-building`, executed tests, and returned control to the terminal. The failure mode changed from `Process spawn via launchd failed / Code 24 / blinking cursor` to ordinary test execution with the fixture project's expected intentional failures.
96+
**Evidence:**
97+
- Cleanup removed all matching orphan streams: count changed from `81` to `0`.
98+
- Post-cleanup verification command:
99+
```sh
100+
python3 - <<'PY'
101+
import subprocess, time
102+
cmd = ['xcrun','simctl','get_app_container','01DA97D9-3856-46C5-A75E-DDD48100B2DB','io.sentry.calculatorapp','app']
103+
start = time.time()
104+
out = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
105+
print('STATUS:completed')
106+
print('RC:', out.returncode)
107+
print('ELAPSED_MS:', int((time.time()-start)*1000))
108+
print('STDOUT:', out.stdout.strip())
109+
PY
110+
```
111+
returned `STATUS:completed`, `RC: 0`, and `ELAPSED_MS: 259` with a valid app-container path.
112+
- Real test command:
113+
```sh
114+
node build/cli.js simulator test --workspace-path /Volumes/Developer/XcodeBuildMCP/example_projects/iOS_Calculator/CalculatorApp.xcworkspace --scheme CalculatorApp --simulator-id 01DA97D9-3856-46C5-A75E-DDD48100B2DB --output raw
115+
```
116+
completed and returned exit code `1` only because the fixture suite contains intentional failures. Final output included:
117+
- `IDETestOperationsObserverDebug: 16.342 elapsed -- Testing started completed.`
118+
- `** TEST EXECUTE FAILED **`
119+
- result bundle path under `/Users/cameroncooke/Library/Developer/XcodeBuildMCP/DerivedData/Logs/Test/...`
120+
- Critically, the rerun did **not** reproduce `Process spawn via launchd failed`, `NSPOSIXErrorDomain Code 24`, or the terminal hang.
121+
**Conclusion:** Confirmed. Clearing the leaked OSLog stream processes restored simulator health sufficiently for the original test path to run normally. The leak is the verified cause of the broken simulator state behind the original symptom.
122+
123+
### Phase 7 - Eliminated hypotheses
124+
**Hypothesis:** `test_sim` directly creates the leaked `simctl spawn ... log stream ...` children.
125+
**Findings:** `test_sim` does not call `launchSimulatorAppWithLogging()` or `startOsLogStream()`.
126+
**Evidence:**
127+
- `src/mcp/tools/simulator/test_sim.ts` routes into `src/utils/test-common.ts` and xcodebuild orchestration, not simulator launch-with-logging.
128+
- The actual spawn site is `src/utils/simulator-steps.ts:251-281`.
129+
**Conclusion:** Eliminated. `test_sim` is not the direct source of the observed orphan stream processes.
130+
131+
## Root Cause
132+
There is a definitive product-side leak in XcodeBuildMCP’s simulator launch-with-logging path.
133+
134+
`launchSimulatorAppWithLogging()` in `src/utils/simulator-steps.ts` starts OSLog capture by calling `startOsLogStream()` (`src/utils/simulator-steps.ts:205`). `startOsLogStream()` then launches:
135+
136+
```ts
137+
xcrun simctl spawn <simulatorUuid> log stream --level=debug --predicate subsystem == "<bundleId>"
138+
```
139+
140+
using `detached: true` (`src/utils/simulator-steps.ts:278`) and immediately `child.unref()` (`src/utils/simulator-steps.ts:281`). The process handle is not stored in any registry, and the normal stop path only runs `simctl terminate` on the app (`src/mcp/tools/simulator/stop_app_sim.ts:58`). Therefore these OSLog stream children are not tied to app lifecycle, not visible in tracked simulator log-session state, and not cleaned up by the normal stop tool.
141+
142+
This was verified with real production code and real process-table inspection:
143+
- the helper created the exact orphaned `simctl spawn ... log stream ...` process shape seen in the field,
144+
- the process lived under PID 1 after the parent exited,
145+
- `simulator stop` did not remove it,
146+
- and repeated launches accumulated multiple survivors.
147+
148+
This was verified end-to-end with real recovery evidence: after removing the leaked stream processes, simulator metadata calls succeeded again and the original `simulator test` command stopped failing in the launch path. In other words, `Code 24` was Xcode/CoreSimulator reporting the downstream effect — an unhealthy simulator launch environment caused by the leaked detached helpers — rather than a separate root cause inside the test suite itself.
149+
150+
## Recommendations
151+
1. Track OSLog stream children from `src/utils/simulator-steps.ts` in an explicit registry.
152+
- File: `src/utils/simulator-steps.ts`
153+
- Record PID/process handle, simulator id, bundle id, and log path.
154+
2. Stop tracked OSLog stream children when the app is stopped.
155+
- File: `src/mcp/tools/simulator/stop_app_sim.ts`
156+
- Extend stop flow to terminate the matching OSLog stream(s), not just the app.
157+
3. Integrate detached simulator OSLog stream cleanup into shutdown/session lifecycle.
158+
- Files: `src/server/mcp-shutdown.ts`, `src/server/mcp-lifecycle.ts`, `src/utils/session-status.ts`
159+
- Ensure status reflects these children and shutdown cleans them.
160+
4. Add regression tests for lifecycle, not just launch success.
161+
- Files: `src/mcp/tools/simulator/__tests__/launch_app_sim.test.ts`, `src/mcp/tools/simulator/__tests__/stop_app_sim.test.ts`, `src/utils/__tests__/simulator-steps-pid.test.ts`
162+
- Assert launch creates tracked OSLog capture and stop/shutdown removes it.
163+
5. Add a doctor/cleanup path for existing leaked simulator OSLog streams.
164+
- Detect orphaned `simctl spawn <sim> log stream ...` helpers and terminate them before they poison later runs.
165+
166+
## Preventive Measures
167+
- Never start detached helper processes without a matching ownership and teardown model.
168+
- Surface all long-lived simulator-side helpers in session status.
169+
- Add an integration test that repeatedly launches/stops an app and asserts no monotonic growth in matching `simctl`/`xcodebuild` processes.
170+
- Add a cleanup command or doctor check that detects and reports orphaned simulator OSLog streams.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"mcpServers": {
3+
"XcodeBuildMCP": {
4+
"type": "stdio",
5+
"command": "node",
6+
"args": [
7+
"../../build/cli.js",
8+
"mcp"
9+
],
10+
"env": {}
11+
}
12+
}
13+
}

src/mcp/resources/__tests__/session-status.test.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,45 @@
1+
import { mkdtempSync } from 'node:fs';
2+
import { rm } from 'node:fs/promises';
3+
import { tmpdir } from 'node:os';
4+
import * as path from 'node:path';
5+
import { EventEmitter } from 'node:events';
6+
import type { ChildProcess } from 'node:child_process';
17
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
28
import { clearDaemonActivityRegistry } from '../../../daemon/activity-registry.ts';
39
import { getDefaultDebuggerManager } from '../../../utils/debugger/index.ts';
410
import { activeLogSessions } from '../../../utils/log_capture.ts';
511
import { activeDeviceLogSessions } from '../../../utils/log-capture/device-log-sessions.ts';
12+
import {
13+
clearAllSimulatorLaunchOsLogSessionsForTests,
14+
registerSimulatorLaunchOsLogSession,
15+
setSimulatorLaunchOsLogRegistryDirOverrideForTests,
16+
} from '../../../utils/log-capture/simulator-launch-oslog-sessions.ts';
17+
import { setSimulatorLaunchOsLogRecordActiveOverrideForTests } from '../../../utils/log-capture/simulator-launch-oslog-registry.ts';
18+
import { setRuntimeInstanceForTests } from '../../../utils/runtime-instance.ts';
619
import { clearAllProcesses } from '../../tools/swift-package/active-processes.ts';
720
import { sessionStatusResourceLogic } from '../session-status.ts';
821

22+
let registryDir: string;
23+
24+
function createTrackedChild(pid = 777): ChildProcess {
25+
const emitter = new EventEmitter();
26+
const child = emitter as ChildProcess;
27+
Object.defineProperty(child, 'pid', { value: pid, configurable: true });
28+
Object.defineProperty(child, 'exitCode', { value: null, writable: true, configurable: true });
29+
child.kill = (() => true) as ChildProcess['kill'];
30+
return child;
31+
}
32+
933
describe('session-status resource', () => {
1034
beforeEach(async () => {
35+
registryDir = mkdtempSync(path.join(tmpdir(), 'xcodebuildmcp-session-status-'));
36+
setSimulatorLaunchOsLogRegistryDirOverrideForTests(registryDir);
37+
setRuntimeInstanceForTests({ instanceId: 'session-status-test', pid: process.pid });
38+
setSimulatorLaunchOsLogRecordActiveOverrideForTests(async () => true);
1139
activeLogSessions.clear();
1240
activeDeviceLogSessions.clear();
1341
clearAllProcesses();
42+
await clearAllSimulatorLaunchOsLogSessionsForTests();
1443
clearDaemonActivityRegistry();
1544
await getDefaultDebuggerManager().disposeAll();
1645
});
@@ -19,8 +48,13 @@ describe('session-status resource', () => {
1948
activeLogSessions.clear();
2049
activeDeviceLogSessions.clear();
2150
clearAllProcesses();
51+
await clearAllSimulatorLaunchOsLogSessionsForTests();
2252
clearDaemonActivityRegistry();
2353
await getDefaultDebuggerManager().disposeAll();
54+
setSimulatorLaunchOsLogRecordActiveOverrideForTests(null);
55+
setRuntimeInstanceForTests(null);
56+
setSimulatorLaunchOsLogRegistryDirOverrideForTests(null);
57+
await rm(registryDir, { recursive: true, force: true });
2458
});
2559

2660
describe('Handler Functionality', () => {
@@ -31,6 +65,7 @@ describe('session-status resource', () => {
3165
const parsed = JSON.parse(result.contents[0].text);
3266

3367
expect(parsed.logging.simulator.activeSessionIds).toEqual([]);
68+
expect(parsed.logging.simulator.activeLaunchOsLogSessions).toEqual([]);
3469
expect(parsed.logging.device.activeSessionIds).toEqual([]);
3570
expect(parsed.debug.currentSessionId).toBe(null);
3671
expect(parsed.debug.sessionIds).toEqual([]);
@@ -43,5 +78,27 @@ describe('session-status resource', () => {
4378
expect(parsed.process.rssBytes).toBeTypeOf('number');
4479
expect(parsed.process.heapUsedBytes).toBeTypeOf('number');
4580
});
81+
82+
it('should include tracked launch OSLog sessions', async () => {
83+
await registerSimulatorLaunchOsLogSession({
84+
process: createTrackedChild(888),
85+
simulatorUuid: 'sim-1',
86+
bundleId: 'io.sentry.app',
87+
logFilePath: '/tmp/app.log',
88+
});
89+
90+
const result = await sessionStatusResourceLogic();
91+
const parsed = JSON.parse(result.contents[0].text);
92+
93+
expect(parsed.logging.simulator.activeLaunchOsLogSessions).toEqual([
94+
expect.objectContaining({
95+
simulatorUuid: 'sim-1',
96+
bundleId: 'io.sentry.app',
97+
pid: 888,
98+
logFilePath: '/tmp/app.log',
99+
ownedByCurrentProcess: true,
100+
}),
101+
]);
102+
});
46103
});
47104
});

src/mcp/resources/session-status.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@
55
*/
66

77
import { log } from '../../utils/logging/index.ts';
8+
import { toErrorMessage } from '../../utils/errors.ts';
89
import { getSessionRuntimeStatusSnapshot } from '../../utils/session-status.ts';
910

1011
export async function sessionStatusResourceLogic(): Promise<{ contents: Array<{ text: string }> }> {
1112
try {
1213
log('info', 'Processing session status resource request');
13-
const status = getSessionRuntimeStatusSnapshot();
14+
const status = await getSessionRuntimeStatusSnapshot();
1415

1516
return {
1617
contents: [
@@ -20,7 +21,7 @@ export async function sessionStatusResourceLogic(): Promise<{ contents: Array<{
2021
],
2122
};
2223
} catch (error) {
23-
const errorMessage = error instanceof Error ? error.message : String(error);
24+
const errorMessage = toErrorMessage(error);
2425
log('error', `Error in session status resource handler: ${errorMessage}`);
2526

2627
return {

0 commit comments

Comments
 (0)