recappi 0.1.29 → 0.1.31

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/index.js CHANGED
@@ -20091,8 +20091,19 @@ function readCliVersion() {
20091
20091
  var CLI_VERSION = readCliVersion();
20092
20092
 
20093
20093
  // src/record.tsx
20094
- import { chmodSync, existsSync, statSync } from "fs";
20094
+ import {
20095
+ chmodSync,
20096
+ cpSync,
20097
+ existsSync,
20098
+ mkdirSync as mkdirSync2,
20099
+ readFileSync as readFileSync2,
20100
+ renameSync,
20101
+ rmSync as rmSync2,
20102
+ statSync,
20103
+ writeFileSync
20104
+ } from "fs";
20095
20105
  import { createRequire as createRequire2 } from "module";
20106
+ import { homedir } from "os";
20096
20107
  import { dirname, join as join2 } from "path";
20097
20108
  import { fileURLToPath } from "url";
20098
20109
  import { render, useInput as useInput2 } from "ink";
@@ -20373,14 +20384,31 @@ function spawnLaunchServicesSidecar(opts) {
20373
20384
  return {
20374
20385
  client,
20375
20386
  kill: () => {
20387
+ requestLaunchServicesSidecarShutdown(input);
20376
20388
  client.close();
20377
20389
  input.end();
20378
20390
  output.destroy();
20379
- child.kill();
20391
+ const killTimer = setTimeout(() => child.kill(), 2e3);
20392
+ killTimer.unref?.();
20393
+ child.once("exit", () => clearTimeout(killTimer));
20380
20394
  cleanup();
20381
20395
  }
20382
20396
  };
20383
20397
  }
20398
+ function requestLaunchServicesSidecarShutdown(input) {
20399
+ try {
20400
+ input.write(
20401
+ `${JSON.stringify({
20402
+ jsonrpc: "2.0",
20403
+ id: "shutdown",
20404
+ method: "recappi.shutdown",
20405
+ params: {}
20406
+ })}
20407
+ `
20408
+ );
20409
+ } catch {
20410
+ }
20411
+ }
20384
20412
  function createFifo(path6) {
20385
20413
  const result = spawnSync("mkfifo", [path6], { encoding: "utf8" });
20386
20414
  if (result.status !== 0) {
@@ -20668,7 +20696,7 @@ function resolveSidecarCommand(opts) {
20668
20696
  const command = opts.sidecarCommand?.trim() || opts.env?.[SIDECAR_COMMAND_ENV]?.trim();
20669
20697
  if (command) return command;
20670
20698
  const bundled = bundledSidecarCommand(process.platform, process.arch);
20671
- if (bundled && existsSync(bundled)) return ensureBundledHelperExecutable(bundled);
20699
+ if (bundled && existsSync(bundled)) return ensureBundledHelperExecutable(bundled, opts);
20672
20700
  const platform = `${process.platform}-${process.arch}`;
20673
20701
  if (bundled) {
20674
20702
  throw cliError("record.helper_unavailable", "Recappi recording helper is not available.", {
@@ -20679,16 +20707,17 @@ function resolveSidecarCommand(opts) {
20679
20707
  hint: `No bundled helper is registered for ${platform}. Set ${SIDECAR_COMMAND_ENV} to a compatible helper when one is available.`
20680
20708
  });
20681
20709
  }
20682
- function ensureBundledHelperExecutable(path6) {
20710
+ function ensureBundledHelperExecutable(path6, opts = {}) {
20683
20711
  if (process.platform === "darwin" && path6.endsWith(".app")) {
20684
- const executable = darwinAppExecutablePath(path6);
20712
+ const stableApp = ensureStableDarwinHelperApp(path6, opts);
20713
+ const executable = darwinAppExecutablePath(stableApp);
20685
20714
  if (!existsSync(executable)) {
20686
20715
  throw cliError("record.helper_unavailable", "Recappi recording helper is not available.", {
20687
- hint: `Expected bundled helper executable inside ${path6}. Reinstall recappi, or set ${SIDECAR_COMMAND_ENV} to a compatible helper.`
20716
+ hint: `Expected bundled helper executable inside ${stableApp}. Reinstall recappi, or set ${SIDECAR_COMMAND_ENV} to a compatible helper.`
20688
20717
  });
20689
20718
  }
20690
20719
  ensureExecutableMode(executable);
20691
- return path6;
20720
+ return stableApp;
20692
20721
  }
20693
20722
  if (process.platform === "win32") return path6;
20694
20723
  ensureExecutableMode(path6);
@@ -20706,6 +20735,54 @@ function ensureExecutableMode(path6) {
20706
20735
  });
20707
20736
  }
20708
20737
  }
20738
+ function ensureStableDarwinHelperApp(sourceApp, opts = {}) {
20739
+ const targetApp = stableDarwinHelperAppPath(opts);
20740
+ const markerPath = join2(dirname(targetApp), ".recappi-helper-source");
20741
+ const signature = helperSourceSignature(sourceApp);
20742
+ const currentSignature = readTextIfExists(markerPath);
20743
+ if (existsSync(darwinAppExecutablePath(targetApp)) && currentSignature === signature) {
20744
+ return targetApp;
20745
+ }
20746
+ const tempApp = `${targetApp}.tmp-${process.pid}-${Date.now()}`;
20747
+ try {
20748
+ mkdirSync2(dirname(targetApp), { recursive: true });
20749
+ rmSync2(tempApp, { recursive: true, force: true });
20750
+ cpSync(sourceApp, tempApp, { recursive: true });
20751
+ ensureExecutableMode(darwinAppExecutablePath(tempApp));
20752
+ rmSync2(targetApp, { recursive: true, force: true });
20753
+ renameSync(tempApp, targetApp);
20754
+ writeFileSync(markerPath, signature);
20755
+ return targetApp;
20756
+ } catch (error51) {
20757
+ rmSync2(tempApp, { recursive: true, force: true });
20758
+ const message = error51 instanceof Error ? error51.message : String(error51);
20759
+ throw cliError("record.helper_unavailable", "Recappi recording helper could not be installed.", {
20760
+ hint: `Could not prepare the local recorder at ${targetApp}: ${message}. Reinstall recappi, or set ${SIDECAR_COMMAND_ENV} to a compatible helper.`
20761
+ });
20762
+ }
20763
+ }
20764
+ function stableDarwinHelperAppPath(opts = {}) {
20765
+ const base = opts.env?.RECAPPI_HELPER_HOME?.trim() || join2(opts.homeDir ?? homedir(), "Library", "Application Support", "Recappi");
20766
+ return join2(base, SIDECAR_APP_BUNDLE_NAME);
20767
+ }
20768
+ function helperSourceSignature(sourceApp) {
20769
+ const executable = statSync(darwinAppExecutablePath(sourceApp));
20770
+ const info = statSync(join2(sourceApp, "Contents", "Info.plist"));
20771
+ return JSON.stringify({
20772
+ app: SIDECAR_APP_BUNDLE_NAME,
20773
+ executableSize: executable.size,
20774
+ executableMtimeMs: executable.mtimeMs,
20775
+ infoSize: info.size,
20776
+ infoMtimeMs: info.mtimeMs
20777
+ });
20778
+ }
20779
+ function readTextIfExists(path6) {
20780
+ try {
20781
+ return readFileSync2(path6, "utf8");
20782
+ } catch {
20783
+ return null;
20784
+ }
20785
+ }
20709
20786
  function bundledSidecarCommand(platform, arch) {
20710
20787
  const executable = helperExecutableName(platform);
20711
20788
  if (!executable) return null;