@opentag/cli 0.3.2 → 0.3.4

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
@@ -2667,6 +2667,15 @@ var serviceHardeningEnvKeys = [
2667
2667
  "OPENTAG_RATE_LIMIT_MAX_REQUESTS",
2668
2668
  "OPENTAG_RATE_LIMIT_DISABLED"
2669
2669
  ];
2670
+ var launchAgentCliPath = [
2671
+ "/opt/homebrew/bin",
2672
+ "/opt/homebrew/sbin",
2673
+ "/usr/local/bin",
2674
+ "/usr/bin",
2675
+ "/bin",
2676
+ "/usr/sbin",
2677
+ "/sbin"
2678
+ ].join(":");
2670
2679
  function loggerFrom(dependencies) {
2671
2680
  return dependencies.logger ?? console;
2672
2681
  }
@@ -2769,11 +2778,38 @@ function assertMacOS(dependencies) {
2769
2778
  function runLaunchctlOrThrow(dependencies, args, action) {
2770
2779
  const result = launchctlRunner(dependencies)(args);
2771
2780
  if (result.status !== 0) {
2772
- const detail = [result.stderr.trim(), result.stdout.trim()].filter(Boolean).join("\n");
2781
+ const detail = launchctlDetail(result);
2773
2782
  throw new Error(`${action} failed${detail ? `: ${detail}` : "."}`);
2774
2783
  }
2775
2784
  return result;
2776
2785
  }
2786
+ function launchctlDetail(result) {
2787
+ return [result.stderr.trim(), result.stdout.trim()].filter(Boolean).join("\n");
2788
+ }
2789
+ function printLaunchdService(dependencies) {
2790
+ return launchctlRunner(dependencies)(["print", launchdServiceTarget(dependencies)]);
2791
+ }
2792
+ function sleepFrom(dependencies) {
2793
+ return dependencies.sleep ?? ((ms) => new Promise((resolve2) => setTimeout(resolve2, ms)));
2794
+ }
2795
+ async function waitForLaunchdLoaded(dependencies, input = {}) {
2796
+ const intervalMs = input.intervalMs ?? 100;
2797
+ const deadline = Date.now() + (input.timeoutMs ?? 1500);
2798
+ while (true) {
2799
+ if (printLaunchdService(dependencies).status === 0) return true;
2800
+ if (Date.now() >= deadline) return false;
2801
+ await sleepFrom(dependencies)(intervalMs);
2802
+ }
2803
+ }
2804
+ async function waitForLaunchdUnloaded(dependencies, input = {}) {
2805
+ const intervalMs = input.intervalMs ?? 100;
2806
+ const deadline = Date.now() + (input.timeoutMs ?? 1500);
2807
+ while (true) {
2808
+ if (printLaunchdService(dependencies).status !== 0) return true;
2809
+ if (Date.now() >= deadline) return false;
2810
+ await sleepFrom(dependencies)(intervalMs);
2811
+ }
2812
+ }
2777
2813
  function serviceWorkingDirectory(configPath) {
2778
2814
  const config = readCliConfig(configPath);
2779
2815
  return config.daemon.repositories[0]?.checkoutPath ?? dirname2(configPath);
@@ -2850,6 +2886,7 @@ function formatConnectorReadiness(config) {
2850
2886
  function launchAgentEnvironment(options, paths) {
2851
2887
  return {
2852
2888
  OPENTAG_CONFIG_PATH: paths.configPath,
2889
+ PATH: launchAgentCliPath,
2853
2890
  ...serviceHardeningEnvironment(options)
2854
2891
  };
2855
2892
  }
@@ -2889,13 +2926,17 @@ function startService(options = {}, dependencies = {}) {
2889
2926
  const launchctl = launchctlRunner(dependencies);
2890
2927
  const bootstrap = launchctl(["bootstrap", launchdDomain(dependencies), paths.plistPath]);
2891
2928
  if (bootstrap.status !== 0) {
2892
- const print = launchctl(["print", launchdServiceTarget(dependencies)]);
2929
+ const print = printLaunchdService(dependencies);
2893
2930
  if (print.status !== 0) {
2894
- const detail = [bootstrap.stderr.trim(), bootstrap.stdout.trim()].filter(Boolean).join("\n");
2931
+ const detail = launchctlDetail(bootstrap);
2895
2932
  throw new Error(`launchctl bootstrap failed${detail ? `: ${detail}` : "."}`);
2896
2933
  }
2897
2934
  }
2898
- runLaunchctlOrThrow(dependencies, ["kickstart", "-k", launchdServiceTarget(dependencies)], "launchctl kickstart");
2935
+ const kickstart = launchctl(["kickstart", "-k", launchdServiceTarget(dependencies)]);
2936
+ if (kickstart.status !== 0 && printLaunchdService(dependencies).status !== 0) {
2937
+ const detail = launchctlDetail(kickstart);
2938
+ throw new Error(`launchctl kickstart failed${detail ? `: ${detail}` : "."}`);
2939
+ }
2899
2940
  return paths;
2900
2941
  }
2901
2942
  function stopService(options = {}, dependencies = {}) {
@@ -2904,10 +2945,11 @@ function stopService(options = {}, dependencies = {}) {
2904
2945
  if (!installed(paths)) return paths;
2905
2946
  const launchctl = launchctlRunner(dependencies);
2906
2947
  const first = launchctl(["bootout", launchdServiceTarget(dependencies)]);
2907
- if (first.status !== 0 && !isNotLoaded(first)) {
2948
+ if (first.status !== 0) {
2908
2949
  const second = launchctl(["bootout", launchdDomain(dependencies), paths.plistPath]);
2909
2950
  if (second.status !== 0 && !isNotLoaded(second)) {
2910
- const detail = [second.stderr.trim(), first.stderr.trim(), second.stdout.trim(), first.stdout.trim()].filter(Boolean).join("\n");
2951
+ const firstDetail = isNotLoaded(first) ? "" : launchctlDetail(first);
2952
+ const detail = [launchctlDetail(second), firstDetail].filter(Boolean).join("\n");
2911
2953
  throw new Error(`launchctl bootout failed${detail ? `: ${detail}` : "."}`);
2912
2954
  }
2913
2955
  }
@@ -3166,6 +3208,9 @@ async function runServiceInstallCommand(options, dependencies = {}) {
3166
3208
  }
3167
3209
  async function runServiceStartCommand(options, dependencies = {}) {
3168
3210
  const paths = startService(options, dependencies);
3211
+ if (!await waitForLaunchdLoaded(dependencies)) {
3212
+ throw new Error("OpenTag service start did not leave launchd loaded. Run `opentag service status` and `opentag service logs` for details.");
3213
+ }
3169
3214
  loggerFrom(dependencies).log(`OpenTag service started: ${paths.label}`);
3170
3215
  }
3171
3216
  async function runServiceStopCommand(options, dependencies = {}) {
@@ -3174,7 +3219,16 @@ async function runServiceStopCommand(options, dependencies = {}) {
3174
3219
  }
3175
3220
  async function runServiceRestartCommand(options, dependencies = {}) {
3176
3221
  stopService(options, dependencies);
3177
- const paths = startService(options, dependencies);
3222
+ await waitForLaunchdUnloaded(dependencies, { timeoutMs: 1e3 });
3223
+ let paths = startService(options, dependencies);
3224
+ let loaded = await waitForLaunchdLoaded(dependencies, { timeoutMs: 500 });
3225
+ if (!loaded) {
3226
+ paths = startService(options, dependencies);
3227
+ loaded = await waitForLaunchdLoaded(dependencies);
3228
+ }
3229
+ if (!loaded) {
3230
+ throw new Error("OpenTag service restart did not leave launchd loaded. Run `opentag service status` and `opentag service logs` for details.");
3231
+ }
3178
3232
  loggerFrom(dependencies).log(`OpenTag service restarted: ${paths.label}`);
3179
3233
  }
3180
3234
  async function runServiceUninstallCommand(options, dependencies = {}) {