@remcp/runtime 0.2.172 → 0.2.173

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 CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.173 — 2026-10-22
4
+
5
+ - Return initial terminal output promptly after a bounded 175 ms grace when a long-running process writes without exiting.
6
+ - Preserve exit-status reporting for immediately completing commands, timeout upper bounds and process-session read/termination semantics.
7
+ - Add terminal regression tests; retain 83 runtime operation routes and unchanged authorization and device safety controls.
8
+
9
+
3
10
  ## 0.2.172 — 2026-10-22
4
11
 
5
12
  - Add bounded host-wide CPU utilization sampling based on deltas from `os.cpus().times` so the dashboard can display real CPU percentages instead of treating load average as CPU%.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remcp/runtime",
3
- "version": "0.2.172",
3
+ "version": "0.2.173",
4
4
  "description": "First-party ReMCP local device runtime: filesystem, terminal, computer-use, browser, diagnostics and document tools over MCP.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -14,7 +14,6 @@ import {
14
14
  readNewOutput,
15
15
  readOutputRange,
16
16
  totalLines,
17
- waitForProcessExit,
18
17
  waitForProcessActivity,
19
18
  } from '../sessions.mjs';
20
19
  import { clampInteger, fail, requireInteger, requireString, structured, text, truncate } from '../util.mjs';
@@ -66,6 +65,21 @@ function terminalStructured(value, fallbackText) {
66
65
  return structured(bounded, fallbackText);
67
66
  }
68
67
 
68
+ // The start call promises initial output, not process completion. Return once
69
+ // useful output arrives, keeping a short grace window so quick commands can
70
+ // still report their real exit status without requiring a follow-up tool call.
71
+ // Explicit timeout_ms remains an upper bound, including for silent commands.
72
+ async function waitForInitialOutput(session, timeoutMs) {
73
+ const deadline = Date.now() + timeoutMs;
74
+ const graceUntil = Date.now() + Math.min(175, timeoutMs);
75
+ while (!session.exited) {
76
+ const now = Date.now();
77
+ if (now >= deadline || (now >= graceUntil && hasNewOutput(session))) break;
78
+ const wakeAt = now < graceUntil ? Math.min(deadline, graceUntil) : deadline;
79
+ await waitForProcessActivity(session, Math.min(100, Math.max(1, wakeAt - now)));
80
+ }
81
+ }
82
+
69
83
  export async function startProcessTool(args, extra = {}) {
70
84
  const command = requireString(args.command, 'command');
71
85
  const verdict = assertAllowedCommand(command);
@@ -105,7 +119,7 @@ export async function startProcessTool(args, extra = {}) {
105
119
  child.on('exit', (code, signal) => markProcessExited(session, code, signal));
106
120
  child.on('close', (code, signal) => markProcessExited(session, code, signal));
107
121
 
108
- await waitForProcessExit(session, timeoutMs);
122
+ await waitForInitialOutput(session, timeoutMs);
109
123
  const headline = session.exited
110
124
  ? `Process ${session.pid} finished${session.exitCode === null ? '' : ` with code ${session.exitCode}`}${session.signal ? ` (${session.signal})` : ''}.`
111
125
  : `Process ${session.pid} is running.`;