hyperframes 0.6.37 → 0.6.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -54,7 +54,7 @@ var VERSION;
54
54
  var init_version = __esm({
55
55
  "src/version.ts"() {
56
56
  "use strict";
57
- VERSION = true ? "0.6.37" : "0.0.0-dev";
57
+ VERSION = true ? "0.6.38" : "0.0.0-dev";
58
58
  }
59
59
  });
60
60
 
@@ -13232,6 +13232,103 @@ var init_portUtils = __esm({
13232
13232
  }
13233
13233
  });
13234
13234
 
13235
+ // src/utils/orphanCleanup.ts
13236
+ import { execSync } from "child_process";
13237
+ function killOrphanedProcesses() {
13238
+ if (process.platform === "win32") return 0;
13239
+ let killed = 0;
13240
+ for (const name of ["chrome-headless-shell", "chrome_headless_shell"]) {
13241
+ killed += killOrphansByName(name);
13242
+ }
13243
+ killed += killOrphansByName("puppeteer_dev_chrome_profile");
13244
+ return killed;
13245
+ }
13246
+ function killProcessTree(pid, signal = "SIGTERM") {
13247
+ if (process.platform === "win32") return;
13248
+ const descendants = getDescendants(pid);
13249
+ const allPids = [...descendants.reverse(), pid];
13250
+ for (const p2 of allPids) {
13251
+ try {
13252
+ process.kill(p2, signal);
13253
+ } catch {
13254
+ }
13255
+ }
13256
+ if (signal !== "SIGKILL") {
13257
+ setTimeout(() => {
13258
+ for (const p2 of allPids) {
13259
+ try {
13260
+ process.kill(p2, "SIGKILL");
13261
+ } catch {
13262
+ }
13263
+ }
13264
+ }, 500).unref();
13265
+ }
13266
+ }
13267
+ function getDescendants(pid) {
13268
+ let children;
13269
+ try {
13270
+ const raw = execSync(`pgrep -P ${pid}`, { encoding: "utf-8", timeout: 2e3 }).trim();
13271
+ if (!raw) return [];
13272
+ children = raw.split("\n").map((s2) => parseInt(s2, 10)).filter((n) => !isNaN(n) && n > 0);
13273
+ } catch {
13274
+ return [];
13275
+ }
13276
+ const all = [];
13277
+ for (const child of children) {
13278
+ all.push(child);
13279
+ all.push(...getDescendants(child));
13280
+ }
13281
+ return all;
13282
+ }
13283
+ function killOrphansByName(processName) {
13284
+ const uid = getUid();
13285
+ const userFlag = uid !== null ? `-u ${uid} ` : "";
13286
+ let pids;
13287
+ try {
13288
+ const raw = execSync(`pgrep ${userFlag}-f ${processName}`, {
13289
+ encoding: "utf-8",
13290
+ timeout: 3e3
13291
+ }).trim();
13292
+ if (!raw) return 0;
13293
+ pids = raw.split("\n").map((s2) => parseInt(s2, 10)).filter((n) => !isNaN(n) && n > 0);
13294
+ } catch {
13295
+ return 0;
13296
+ }
13297
+ let killed = 0;
13298
+ for (const pid of pids) {
13299
+ if (!isOrphan(pid)) continue;
13300
+ killProcessTree(pid);
13301
+ killed++;
13302
+ }
13303
+ return killed;
13304
+ }
13305
+ function getUid() {
13306
+ if (_cachedUid !== void 0) return _cachedUid;
13307
+ try {
13308
+ _cachedUid = execSync("id -u", { encoding: "utf-8", timeout: 1e3 }).trim();
13309
+ } catch {
13310
+ _cachedUid = null;
13311
+ }
13312
+ return _cachedUid;
13313
+ }
13314
+ function isOrphan(pid) {
13315
+ try {
13316
+ const ppid = execSync(`ps -p ${pid} -o ppid=`, {
13317
+ encoding: "utf-8",
13318
+ timeout: 2e3
13319
+ }).trim();
13320
+ return ppid === "1";
13321
+ } catch {
13322
+ return false;
13323
+ }
13324
+ }
13325
+ var _cachedUid;
13326
+ var init_orphanCleanup = __esm({
13327
+ "src/utils/orphanCleanup.ts"() {
13328
+ "use strict";
13329
+ }
13330
+ });
13331
+
13235
13332
  // src/server/fileWatcher.ts
13236
13333
  import { watch } from "fs";
13237
13334
  function shouldWatchProjectFile(filename) {
@@ -29018,7 +29115,7 @@ __export(manager_exports2, {
29018
29115
  findBrowser: () => findBrowser,
29019
29116
  isLinuxArm: () => isLinuxArm
29020
29117
  });
29021
- import { execSync, spawnSync as spawnSync2 } from "child_process";
29118
+ import { execSync as execSync2, spawnSync as spawnSync2 } from "child_process";
29022
29119
  import { existsSync as existsSync18, readdirSync as readdirSync8, rmSync as rmSync4 } from "fs";
29023
29120
  import { basename as basename2 } from "path";
29024
29121
  import { homedir as homedir5 } from "os";
@@ -29027,7 +29124,7 @@ import { Browser, detectBrowserPlatform, getInstalledBrowsers, install } from "@
29027
29124
  function whichBinary2(name) {
29028
29125
  try {
29029
29126
  const cmd = process.platform === "win32" ? `where ${name}` : `which ${name}`;
29030
- const output = execSync(cmd, {
29127
+ const output = execSync2(cmd, {
29031
29128
  encoding: "utf-8",
29032
29129
  stdio: ["pipe", "pipe", "pipe"],
29033
29130
  timeout: 5e3
@@ -30646,6 +30743,43 @@ var init_frameCapture = __esm({
30646
30743
  }
30647
30744
  });
30648
30745
 
30746
+ // ../engine/src/utils/processTracker.ts
30747
+ function trackChildProcess(proc) {
30748
+ tracked.add(proc);
30749
+ const remove2 = () => tracked.delete(proc);
30750
+ proc.once("exit", remove2);
30751
+ proc.once("error", remove2);
30752
+ }
30753
+ function killTrackedProcesses() {
30754
+ const alive = [];
30755
+ for (const proc of tracked) {
30756
+ if (!proc.killed) {
30757
+ try {
30758
+ proc.kill("SIGTERM");
30759
+ alive.push(proc);
30760
+ } catch {
30761
+ }
30762
+ }
30763
+ }
30764
+ tracked.clear();
30765
+ if (alive.length === 0) return;
30766
+ setTimeout(() => {
30767
+ for (const proc of alive) {
30768
+ try {
30769
+ proc.kill("SIGKILL");
30770
+ } catch {
30771
+ }
30772
+ }
30773
+ }, 500).unref();
30774
+ }
30775
+ var tracked;
30776
+ var init_processTracker = __esm({
30777
+ "../engine/src/utils/processTracker.ts"() {
30778
+ "use strict";
30779
+ tracked = /* @__PURE__ */ new Set();
30780
+ }
30781
+ });
30782
+
30649
30783
  // ../engine/src/utils/gpuEncoder.ts
30650
30784
  import { spawn as spawn4 } from "child_process";
30651
30785
  async function detectGpuEncoder() {
@@ -30787,6 +30921,7 @@ async function runFfmpeg(args, opts) {
30787
30921
  const onStderr = opts?.onStderr;
30788
30922
  return new Promise((resolve46) => {
30789
30923
  const ffmpeg = spawn5("ffmpeg", args);
30924
+ trackChildProcess(ffmpeg);
30790
30925
  let stderr = "";
30791
30926
  const onAbort = () => {
30792
30927
  ffmpeg.kill("SIGTERM");
@@ -30834,6 +30969,7 @@ var DEFAULT_TIMEOUT, DEFAULT_STDERR_TAIL_LINES;
30834
30969
  var init_runFfmpeg = __esm({
30835
30970
  "../engine/src/utils/runFfmpeg.ts"() {
30836
30971
  "use strict";
30972
+ init_processTracker();
30837
30973
  DEFAULT_TIMEOUT = 3e5;
30838
30974
  DEFAULT_STDERR_TAIL_LINES = 15;
30839
30975
  }
@@ -31075,6 +31211,7 @@ async function encodeFramesFromDir(framesDir, framePattern, outputPath, options,
31075
31211
  const args = buildEncoderArgs(options, inputArgs, outputPath, gpuEncoder);
31076
31212
  return new Promise((resolve46) => {
31077
31213
  const ffmpeg = spawn6("ffmpeg", args);
31214
+ trackChildProcess(ffmpeg);
31078
31215
  let stderr = "";
31079
31216
  const onAbort = () => {
31080
31217
  ffmpeg.kill("SIGTERM");
@@ -31185,6 +31322,7 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
31185
31322
  const args = buildEncoderArgs(options, inputArgs, chunkPath, gpuEncoder);
31186
31323
  const chunkResult = await new Promise((resolve46) => {
31187
31324
  const ffmpeg = spawn6("ffmpeg", args);
31325
+ trackChildProcess(ffmpeg);
31188
31326
  let stderr = "";
31189
31327
  ffmpeg.stderr.on("data", (d2) => {
31190
31328
  stderr += d2.toString();
@@ -31226,6 +31364,7 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
31226
31364
  ];
31227
31365
  const concatResult = await new Promise((resolve46) => {
31228
31366
  const ffmpeg = spawn6("ffmpeg", concatArgs);
31367
+ trackChildProcess(ffmpeg);
31229
31368
  let stderr = "";
31230
31369
  ffmpeg.stderr.on("data", (d2) => {
31231
31370
  stderr += d2.toString();
@@ -31316,6 +31455,7 @@ var ENCODER_PRESETS;
31316
31455
  var init_chunkEncoder = __esm({
31317
31456
  "../engine/src/services/chunkEncoder.ts"() {
31318
31457
  "use strict";
31458
+ init_processTracker();
31319
31459
  init_config2();
31320
31460
  init_gpuEncoder();
31321
31461
  init_hdr();
@@ -31544,6 +31684,7 @@ async function spawnStreamingEncoder(outputPath, options, signal, config) {
31544
31684
  const ffmpeg = spawn7("ffmpeg", args, {
31545
31685
  stdio: ["pipe", "pipe", "pipe"]
31546
31686
  });
31687
+ trackChildProcess(ffmpeg);
31547
31688
  let exitStatus = "running";
31548
31689
  let stderr = "";
31549
31690
  let exitCode = null;
@@ -31640,6 +31781,7 @@ Process error: ${err.message}`;
31640
31781
  var init_streamingEncoder = __esm({
31641
31782
  "../engine/src/services/streamingEncoder.ts"() {
31642
31783
  "use strict";
31784
+ init_processTracker();
31643
31785
  init_gpuEncoder();
31644
31786
  init_runFfmpeg();
31645
31787
  init_hdr();
@@ -33660,6 +33802,7 @@ async function extractVideoFramesRange(videoPath, videoId, startTime, duration,
33660
33802
  args.push("-y", outputPattern);
33661
33803
  return new Promise((resolve46, reject) => {
33662
33804
  const ffmpeg = spawn9("ffmpeg", args);
33805
+ trackChildProcess(ffmpeg);
33663
33806
  let stderr = "";
33664
33807
  const onAbort = () => {
33665
33808
  ffmpeg.kill("SIGTERM");
@@ -34122,6 +34265,7 @@ var init_videoFrameExtractor = __esm({
34122
34265
  "../engine/src/services/videoFrameExtractor.ts"() {
34123
34266
  "use strict";
34124
34267
  init_esm10();
34268
+ init_processTracker();
34125
34269
  init_ffprobe();
34126
34270
  init_hdr();
34127
34271
  init_urlDownloader();
@@ -36858,6 +37002,7 @@ __export(src_exports2, {
36858
37002
  injectVideoFramesBatch: () => injectVideoFramesBatch,
36859
37003
  isHdrColorSpace: () => isHdrColorSpace,
36860
37004
  isHttpUrl: () => isHttpUrl,
37005
+ killTrackedProcesses: () => killTrackedProcesses,
36861
37006
  launchHdrBrowser: () => launchHdrBrowser,
36862
37007
  linearToHdr: () => linearToHdr,
36863
37008
  mergeWorkerFrames: () => mergeWorkerFrames,
@@ -36888,6 +37033,7 @@ __export(src_exports2, {
36888
37033
  showVideoElements: () => showVideoElements,
36889
37034
  spawnStreamingEncoder: () => spawnStreamingEncoder,
36890
37035
  syncVideoFrameVisibility: () => syncVideoFrameVisibility,
37036
+ trackChildProcess: () => trackChildProcess,
36891
37037
  uploadAndReadbackHdrFrame: () => uploadAndReadbackHdrFrame
36892
37038
  });
36893
37039
  var init_src2 = __esm({
@@ -36910,6 +37056,7 @@ var init_src2 = __esm({
36910
37056
  init_ffprobe();
36911
37057
  init_urlDownloader();
36912
37058
  init_runFfmpeg();
37059
+ init_processTracker();
36913
37060
  init_alphaBlit();
36914
37061
  init_layerCompositor();
36915
37062
  init_shaderTransitions();
@@ -45385,6 +45532,7 @@ var init_src3 = __esm({
45385
45532
  // src/server/studioServer.ts
45386
45533
  var studioServer_exports = {};
45387
45534
  __export(studioServer_exports, {
45535
+ closeThumbnailBrowser: () => closeThumbnailBrowser,
45388
45536
  createStudioServer: () => createStudioServer,
45389
45537
  resolveStudioBundle: () => resolveStudioBundle
45390
45538
  });
@@ -45480,16 +45628,6 @@ async function getThumbnailBrowser() {
45480
45628
  _thumbnailBrowser = null;
45481
45629
  _thumbnailBrowserInitializing = null;
45482
45630
  });
45483
- const onExit = async () => {
45484
- const { releaseBrowser: releaseBrowser2 } = await Promise.resolve().then(() => (init_src2(), src_exports2));
45485
- if (_thumbnailBrowser) {
45486
- await releaseBrowser2(_thumbnailBrowser).catch(() => {
45487
- });
45488
- _thumbnailBrowser = null;
45489
- }
45490
- };
45491
- process.once("SIGTERM", () => void onExit());
45492
- process.once("SIGINT", () => void onExit());
45493
45631
  return _thumbnailBrowser;
45494
45632
  } catch (err) {
45495
45633
  console.warn(
@@ -45502,6 +45640,15 @@ async function getThumbnailBrowser() {
45502
45640
  })();
45503
45641
  return _thumbnailBrowserInitializing;
45504
45642
  }
45643
+ async function closeThumbnailBrowser() {
45644
+ if (!_thumbnailBrowser) return;
45645
+ const browser = _thumbnailBrowser;
45646
+ _thumbnailBrowser = null;
45647
+ _thumbnailBrowserInitializing = null;
45648
+ const { releaseBrowser: releaseBrowser2 } = await Promise.resolve().then(() => (init_src2(), src_exports2));
45649
+ await releaseBrowser2(browser).catch(() => {
45650
+ });
45651
+ }
45505
45652
  function createStudioServer(options) {
45506
45653
  const { projectDir, projectName } = options;
45507
45654
  const projectId = projectName || basename5(projectDir);
@@ -45949,6 +46096,11 @@ async function runDevMode(dir, options) {
45949
46096
  }
45950
46097
  });
45951
46098
  }
46099
+ const shutdown = () => {
46100
+ if (child.pid) killProcessTree(child.pid);
46101
+ };
46102
+ process.once("SIGINT", shutdown);
46103
+ process.once("SIGTERM", shutdown);
45952
46104
  return new Promise((resolve46) => {
45953
46105
  child.on("close", () => resolve46());
45954
46106
  });
@@ -46024,6 +46176,11 @@ async function runLocalStudioMode(dir, options) {
46024
46176
  }
46025
46177
  });
46026
46178
  }
46179
+ const shutdown = () => {
46180
+ if (child.pid) killProcessTree(child.pid);
46181
+ };
46182
+ process.once("SIGINT", shutdown);
46183
+ process.once("SIGTERM", shutdown);
46027
46184
  return new Promise((resolve46) => {
46028
46185
  child.on("close", () => resolve46());
46029
46186
  });
@@ -46118,11 +46275,29 @@ async function runEmbeddedMode(dir, startPort, options) {
46118
46275
  rl?.close();
46119
46276
  console.log();
46120
46277
  console.log(` ${c2.dim("Shutting down studio...")}`);
46121
- result.server.close(() => resolveRun());
46122
- setTimeout(() => process.exit(0), 2e3).unref();
46278
+ setTimeout(() => process.exit(0), 3e3).unref();
46279
+ const cleanup = async () => {
46280
+ const { closeThumbnailBrowser: closeThumbnailBrowser2 } = await Promise.resolve().then(() => (init_studioServer(), studioServer_exports));
46281
+ const { drainBrowserPool: drainBrowserPool2, killTrackedProcesses: killTrackedProcesses2 } = await Promise.resolve().then(() => (init_src2(), src_exports2));
46282
+ killTrackedProcesses2();
46283
+ await closeThumbnailBrowser2().catch(() => {
46284
+ });
46285
+ await drainBrowserPool2().catch(() => {
46286
+ });
46287
+ };
46288
+ cleanup().catch(() => {
46289
+ }).finally(() => {
46290
+ result.server.close(() => resolveRun());
46291
+ });
46123
46292
  };
46124
46293
  process.once("SIGINT", shutdown);
46125
46294
  process.once("SIGTERM", shutdown);
46295
+ Promise.resolve().then(() => (init_src2(), src_exports2)).then(({ killTrackedProcesses: killTrackedProcesses2 }) => {
46296
+ process.once("exit", () => {
46297
+ if (!shuttingDown) killTrackedProcesses2();
46298
+ });
46299
+ }).catch(() => {
46300
+ });
46126
46301
  });
46127
46302
  }
46128
46303
  var examples, preview_default;
@@ -46137,6 +46312,7 @@ var init_preview2 = __esm({
46137
46312
  init_lintProject();
46138
46313
  init_lintFormat();
46139
46314
  init_portUtils();
46315
+ init_orphanCleanup();
46140
46316
  examples = [
46141
46317
  ["Preview the current project", "hyperframes preview"],
46142
46318
  ["Preview a specific project directory", "hyperframes preview ./my-video"],
@@ -46215,6 +46391,12 @@ var init_preview2 = __esm({
46215
46391
  `);
46216
46392
  return;
46217
46393
  }
46394
+ const orphansKilled = killOrphanedProcesses();
46395
+ if (orphansKilled > 0) {
46396
+ console.log(
46397
+ ` ${c2.dim(`Cleaned up ${orphansKilled} orphaned process${orphansKilled === 1 ? "" : "es"} from a previous session.`)}`
46398
+ );
46399
+ }
46218
46400
  const rawArg = args.dir;
46219
46401
  const dir = resolve25(rawArg ?? ".");
46220
46402
  const isImplicitCwd = !rawArg || rawArg === "." || rawArg === "./";
@@ -48337,11 +48519,11 @@ __export(ffmpeg_exports, {
48337
48519
  findFFmpeg: () => findFFmpeg,
48338
48520
  getFFmpegInstallHint: () => getFFmpegInstallHint
48339
48521
  });
48340
- import { execSync as execSync2 } from "child_process";
48522
+ import { execSync as execSync3 } from "child_process";
48341
48523
  function findFFmpeg() {
48342
48524
  try {
48343
48525
  const cmd = process.platform === "win32" ? "where ffmpeg" : "which ffmpeg";
48344
- const output = execSync2(cmd, {
48526
+ const output = execSync3(cmd, {
48345
48527
  encoding: "utf-8",
48346
48528
  stdio: ["pipe", "pipe", "pipe"],
48347
48529
  timeout: 5e3
@@ -51959,13 +52141,13 @@ __export(doctor_exports, {
51959
52141
  examples: () => examples19,
51960
52142
  redactHome: () => redactHome
51961
52143
  });
51962
- import { execSync as execSync3 } from "child_process";
52144
+ import { execSync as execSync4 } from "child_process";
51963
52145
  import { freemem as freemem5, platform as platform8 } from "os";
51964
52146
  function checkFFmpeg() {
51965
52147
  const path2 = findFFmpeg();
51966
52148
  if (path2) {
51967
52149
  try {
51968
- const version = execSync3("ffmpeg -version", { encoding: "utf-8", timeout: 5e3 }).split("\n")[0] ?? "";
52150
+ const version = execSync4("ffmpeg -version", { encoding: "utf-8", timeout: 5e3 }).split("\n")[0] ?? "";
51969
52151
  return { ok: true, detail: version.trim() };
51970
52152
  } catch {
51971
52153
  return { ok: true, detail: path2 };
@@ -51979,7 +52161,7 @@ function checkFFmpeg() {
51979
52161
  }
51980
52162
  function checkFFprobe() {
51981
52163
  try {
51982
- const version = execSync3("ffprobe -version", { encoding: "utf-8", timeout: 5e3 }).split("\n")[0] ?? "";
52164
+ const version = execSync4("ffprobe -version", { encoding: "utf-8", timeout: 5e3 }).split("\n")[0] ?? "";
51983
52165
  return { ok: true, detail: version.trim() };
51984
52166
  } catch {
51985
52167
  return {
@@ -52002,7 +52184,7 @@ async function checkChrome() {
52002
52184
  }
52003
52185
  function checkDocker() {
52004
52186
  try {
52005
- const version = execSync3("docker --version", { encoding: "utf-8", timeout: 5e3 }).trim();
52187
+ const version = execSync4("docker --version", { encoding: "utf-8", timeout: 5e3 }).trim();
52006
52188
  return { ok: true, detail: version };
52007
52189
  } catch {
52008
52190
  return {
@@ -52014,7 +52196,7 @@ function checkDocker() {
52014
52196
  }
52015
52197
  function checkDockerRunning() {
52016
52198
  try {
52017
- execSync3("docker info", { stdio: "pipe", timeout: 5e3 });
52199
+ execSync4("docker info", { stdio: "pipe", timeout: 5e3 });
52018
52200
  return { ok: true, detail: "Running" };
52019
52201
  } catch {
52020
52202
  return {