Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

[Windows] Three `detached: true` spawns missing `windowsHide` — telemetry flushSync opens a console window on nearly every CLI exit

未关闭
#3,476 1 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

还没有人认领这个 Issue。

  • #3478 来自 @kvnloo —— 已关闭,未合并
  • #3823 来自 @lorenzozanee —— 已关闭,未合并
  • #3851 来自 @dajiaohuang —— 已关闭,未合并

评估

难度
3/5
预计耗时
1-2 天
新手友好度
78/100
Issue 类型
缺陷
描述清晰度
描述清楚
活跃度
冷清
领域
cli

调研方向

Inspect the detached spawns in src/telemetry/transport.ts, src/utils/openBrowser.ts, and src/commands/previewLifecycle.ts, comparing their options with the existing windowsHide handling in src/utils/autoUpdate.ts. Verify on Windows that telemetry flushes, background preview, and browser launches no longer open console windows while preserving their existing detached behavior.

由索引模型根据 Issue 内容生成。

描述

triage/needs-triage
Describe the bug

On Windows, console windows pop up during ordinary CLI use — not just during renders. This is a follow-up to #3379 (ffmpeg, fixed) and is distinct from #3430 (chrome-headless-shell, still open): those two cover console-subsystem binaries, whereas this one is about detached: true spawns of Node itself.

Node's docs are explicit about the mechanism:

On Windows, setting options.detached to true makes it possible for the child process to continue running after the parent exits. The child will have its own console window.

child_process.spawn() defaults windowsHide to false, so any detached: true spawn opens a visible console window on Windows unless windowsHide: true is passed.

Root cause

packages/cli v0.8.13 has four detached: true spawns. Three are missing windowsHide: true:

Source What it spawns windowsHide
src/telemetry/transport.ts (flushSync) node -e "fetch(...)" → PostHog ❌ missing
src/utils/openBrowser.ts (openBrowser) user's browser ❌ missing
src/commands/previewLifecycle.ts background preview server ❌ missing
src/utils/autoUpdate.ts update check ✅ present

autoUpdate.ts already gets this right, which makes the other three look like oversights rather than intent.

The worst offender: telemetry flushSync

flushSync() is the process-exit flush path. Because it can't await an HTTP POST during shutdown, it hands the payload to a detached Node process to deliver after the parent dies:

function flushSync() {
  const payload = buildPayload(eventQueue);
  if (payload == null) return;
  eventQueue = [];
  try {
    const child = spawn(
      process.execPath,
      ["-e", `fetch(${JSON.stringify(`${POSTHOG_HOST}/batch/`)},{...})`],
      { detached: true, stdio: "ignore" }   // <-- no windowsHide
    );
    child.unref();
  } catch {}
}

The strategy itself is sound — the only thing missing is windowsHide: true.

Impact is amplified by how the CLI is actually used. Agent-driven workflows invoke many short-lived commands (check, lint, keyframes, capture, snapshot, beats, preview), and each invocation that exits with queued events opens its own console window. My ~/.hyperframes/config.json shows commandCount: 1350, which is a lot of windows. Unlike #3430 this isn't render-only — it fires on nearly every command, including read-only ones.

Steps to reproduce
  1. On Windows, ensure telemetry is on (default): telemetryEnabled: true in ~/.hyperframes/config.json
  2. Run any short command, e.g. npx hyperframes check . or npx hyperframes lint .
  3. Watch the desktop/taskbar as the command exits — a console window flashes open
  4. Run several commands in sequence; you get one window per exit

Setting HYPERFRAMES_NO_TELEMETRY=1 (or DO_NOT_TRACK=1) makes the flashing stop, which isolates the telemetry spawn as the cause.

For the other two sites: hyperframes preview without --foreground spawns the detached background server (one window), and without --no-open spawns the browser via options.browserPath (one more).

Expected behavior

No console window appears for any of these background spawns.

Actual behavior

A console window opens per detached spawn — in the telemetry case, on nearly every CLI invocation.

Suggested fix

Add windowsHide: true at the three call sites, matching what autoUpdate.ts already does:

// src/telemetry/transport.ts
const child = spawn(process.execPath, ["-e", script], {
  detached: true,
  stdio: "ignore",
  windowsHide: true,
});

// src/utils/openBrowser.ts
const child = spawn7(options.browserPath, args, {
  detached: true,
  stdio: "ignore",
  windowsHide: true,
});

// src/commands/previewLifecycle.ts
child = spawn17(execPath, args, {
  detached: true,
  stdio: ["ignore", logFd, logFd],
  env: process.env,
  windowsHide: true,
});

windowsHide is a no-op on macOS/Linux, so it's safe to apply unconditionally — same rationale as the #3379 fix.

Given that #3379, #3430, and this issue are all the same class of defect, it may be worth a small shared spawn helper that applies windowsHide: true by default, plus a lint rule that flags a bare detached: true without it.

Environment
hyperframes  0.8.13 (latest)
Node.js      v24.15.0 (win32 x64)
OS           Microsoft Windows 10 Home 10.0.19045 (build 19045)
Install      npx (_npx cache)
Additional context

Verified by static analysis of the shipped dist/cli.js in [email protected] — all four detached: true sites were inspected directly, along with every windowsHide occurrence. All ffmpeg/ffprobe spawns correctly carry windowsHide: true with the explanatory comment added by the #3379 fix, so that regression has not returned.

Related: #3379 (ffmpeg, closed/fixed) · #3430 (chrome-headless-shell, open)

主要语言
TypeScript
星标
54.1k
派生
4.9k
平均合并
7 小时 2 分钟
30 天内合并 PR
782

环境准备

这个项目没有提供开发容器、Dockerfile 或贡献指南,环境需要你自己搭建:先看它的 README,通用步骤见我们的新手贡献指南。

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

heygen-com/hyperframes 的其他 Issue

查看 heygen-com/hyperframes 的全部 Issue

相似的 Issue

更多 TypeScript Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。