overlord-cli 0.2608231148.0 → 0.2608241435.0

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
@@ -7375,6 +7375,9 @@ function hasControlCharacters(value) {
7375
7375
  function hasUnsafePathCharacters(value) {
7376
7376
  return hasControlCharacters(value) || value.includes("\\");
7377
7377
  }
7378
+ function isOverlordManagedEvidencePath(filePath) {
7379
+ return filePath === ".overlord" || filePath.startsWith(".overlord/");
7380
+ }
7378
7381
  function isExactEvidencePath(value) {
7379
7382
  if (typeof value !== "string")
7380
7383
  return false;
@@ -19247,6 +19250,7 @@ function normalizeWorkspacePath({
19247
19250
  }
19248
19251
  if (relative.length > MAX_EVIDENCE_PATH_LENGTH) return { reason: "path_too_long" };
19249
19252
  if (!isExactEvidencePath(relative)) return { reason: "invalid_path" };
19253
+ if (isOverlordManagedEvidencePath(relative)) return { reason: "ignored_path" };
19250
19254
  if (isIgnoredPath(ignoreRules, relative)) return { reason: "ignored_path" };
19251
19255
  return { filePath: relative };
19252
19256
  }
@@ -20809,6 +20813,9 @@ var init_pre_launch = __esm({
20809
20813
  });
20810
20814
 
20811
20815
  // src/terminal-launcher.ts
20816
+ function terminalOpenSpawnTimeoutMs(execution) {
20817
+ return execution.terminal ? TERMINAL_OPEN_SPAWN_TIMEOUT_MS : void 0;
20818
+ }
20812
20819
  function shellQuote2(value) {
20813
20820
  return `'${value.replace(/'/g, `'\\''`)}'`;
20814
20821
  }
@@ -21126,11 +21133,14 @@ function resolveLaunchExecution({
21126
21133
  });
21127
21134
  return { command: full, args: [], useShell: true, terminal: launcher, display: full };
21128
21135
  }
21136
+ var TERMINAL_OPEN_SPAWN_TIMEOUT_MS, TERMINAL_OPEN_SPAWN_KILL_SIGNAL;
21129
21137
  var init_terminal_launcher = __esm({
21130
21138
  "src/terminal-launcher.ts"() {
21131
21139
  "use strict";
21132
21140
  init_project_tmp();
21133
21141
  init_terminal_launch_chord();
21142
+ TERMINAL_OPEN_SPAWN_TIMEOUT_MS = 45e3;
21143
+ TERMINAL_OPEN_SPAWN_KILL_SIGNAL = "SIGKILL";
21134
21144
  }
21135
21145
  });
21136
21146
 
@@ -21142,6 +21152,40 @@ function interactiveLoginShellInvocation(command, configuredShell = process.env.
21142
21152
  const shell = configuredShell?.trim() || "/bin/bash";
21143
21153
  return { command: shell, args: ["-ilc", command] };
21144
21154
  }
21155
+ function spawnSyncOptionsForLaunch({
21156
+ cwd,
21157
+ env,
21158
+ timeoutMs
21159
+ }) {
21160
+ return {
21161
+ cwd,
21162
+ env,
21163
+ stdio: "inherit",
21164
+ ...timeoutMs === void 0 ? {} : { timeout: timeoutMs, killSignal: TERMINAL_OPEN_SPAWN_KILL_SIGNAL }
21165
+ };
21166
+ }
21167
+ function isSpawnSyncTimedOut(result) {
21168
+ return result.error?.code === "ETIMEDOUT";
21169
+ }
21170
+ function terminalOpenTimeoutMessage({
21171
+ terminal,
21172
+ timeoutMs
21173
+ }) {
21174
+ const seconds = Math.round(timeoutMs / 1e3);
21175
+ return `osascript/Apple Event timed out after ${seconds}s while opening ${terminal}. The execution request failed so the runner can keep claiming. ${terminal} may still open after this timeout (orphan window).`;
21176
+ }
21177
+ function throwIfTerminalOpenTimedOut({
21178
+ result,
21179
+ execution
21180
+ }) {
21181
+ if (!execution.terminal || !isSpawnSyncTimedOut(result)) return;
21182
+ throw new Error(
21183
+ terminalOpenTimeoutMessage({
21184
+ terminal: execution.terminal,
21185
+ timeoutMs: TERMINAL_OPEN_SPAWN_TIMEOUT_MS
21186
+ })
21187
+ );
21188
+ }
21145
21189
  function overlordLaunchEnv({
21146
21190
  backendUrl,
21147
21191
  missionId,
@@ -21573,16 +21617,15 @@ async function launchAgent({
21573
21617
  };
21574
21618
  }
21575
21619
  const { execution } = plan;
21576
- const shellInvocation = execution.useShell ? interactiveLoginShellInvocation(execution.command) : null;
21577
- const result = shellInvocation ? spawnSync3(shellInvocation.command, shellInvocation.args, {
21578
- cwd: options.workingDirectory,
21579
- env,
21580
- stdio: "inherit"
21581
- }) : spawnSync3(execution.command, execution.args, {
21620
+ const timeoutMs = terminalOpenSpawnTimeoutMs(execution);
21621
+ const spawnOptions = spawnSyncOptionsForLaunch({
21582
21622
  cwd: options.workingDirectory,
21583
21623
  env,
21584
- stdio: "inherit"
21624
+ timeoutMs
21585
21625
  });
21626
+ const shellInvocation = execution.useShell ? interactiveLoginShellInvocation(execution.command) : null;
21627
+ const result = shellInvocation ? spawnSync3(shellInvocation.command, shellInvocation.args, spawnOptions) : spawnSync3(execution.command, execution.args, spawnOptions);
21628
+ throwIfTerminalOpenTimedOut({ result, execution });
21586
21629
  return {
21587
21630
  plan,
21588
21631
  status: result.status,
@@ -22795,13 +22838,66 @@ function resolveOvldInvocation(argv = process.argv, execPath = process.execPath)
22795
22838
  }
22796
22839
  return { program: execPath, args: ["runner", "supervise"] };
22797
22840
  }
22841
+ function composeRunnerServicePath({
22842
+ homeDir = os5.homedir()
22843
+ } = {}) {
22844
+ const localBin = path33.join(homeDir, ".local", "bin");
22845
+ const dirs = [...RUNNER_SERVICE_PATH_PREFIX_DIRS, localBin, ...RUNNER_SERVICE_SYSTEM_PATH_DIRS];
22846
+ return [...new Set(dirs)].join(":");
22847
+ }
22848
+ function parseLaunchdProcessType(plist) {
22849
+ const match = /<key>ProcessType<\/key>\s*<string>([^<]*)<\/string>/.exec(plist);
22850
+ return match?.[1] ?? null;
22851
+ }
22852
+ function parseLaunchdEnvPath(plist) {
22853
+ const match = /<key>PATH<\/key>\s*<string>([^<]*)<\/string>/.exec(plist);
22854
+ return match?.[1] ?? null;
22855
+ }
22856
+ function inspectInstalledLaunchdPlist(plistPath) {
22857
+ if (!existsSync28(plistPath)) return { processType: null, path: null };
22858
+ try {
22859
+ const plist = readFileSync19(plistPath, "utf8");
22860
+ return {
22861
+ processType: parseLaunchdProcessType(plist),
22862
+ path: parseLaunchdEnvPath(plist)
22863
+ };
22864
+ } catch {
22865
+ return { processType: null, path: null };
22866
+ }
22867
+ }
22868
+ function runnerServiceReinstallHint({
22869
+ installed,
22870
+ publisher,
22871
+ processType,
22872
+ path: path36
22873
+ }) {
22874
+ if (!installed) return null;
22875
+ const hints = [];
22876
+ if (publisher === "node") {
22877
+ hints.push(
22878
+ 'This service is registered under "Node.js Foundation" because it runs the plain node binary. Reinstall it from the Overlord desktop app (or with the desktop app present) to re-register it under "Overlord".'
22879
+ );
22880
+ }
22881
+ if (processType && processType !== LAUNCHD_PROCESS_TYPE) {
22882
+ hints.push(
22883
+ `This LaunchAgent is ProcessType=${processType}. App auto-update respawns the supervisor but does not rewrite ProcessType, so Apple Events to Terminal/iTerm stay App-Napped. Reinstall with \`ovld runner service install\` (or Desktop \u2192 Reinstall service) to switch to ${LAUNCHD_PROCESS_TYPE}.`
22884
+ );
22885
+ }
22886
+ if (path36 !== void 0 && path36 !== composeRunnerServicePath()) {
22887
+ hints.push(
22888
+ "This LaunchAgent PATH is not the deterministic prefix (`/opt/homebrew/bin:/usr/local/bin:$HOME/.local/bin` plus system dirs). App auto-update respawns the supervisor but does not rewrite PATH, so Latch/`open`/agent binaries spawned by the service may be missing. Reinstall with `ovld runner service install` (or Desktop \u2192 Reinstall service) to apply it."
22889
+ );
22890
+ }
22891
+ return hints.length > 0 ? hints.join(" ") : null;
22892
+ }
22798
22893
  function buildRunnerServiceEnv({
22799
22894
  backendUrl,
22800
22895
  overlordHome,
22801
- runAsElectronNode
22896
+ runAsElectronNode,
22897
+ homeDir
22802
22898
  }) {
22803
22899
  const env = {
22804
- PATH: process.env.PATH?.trim() || "/usr/local/bin:/usr/bin:/bin"
22900
+ PATH: composeRunnerServicePath({ homeDir })
22805
22901
  };
22806
22902
  if (!isLoopbackBackendUrl(backendUrl)) env.OVERLORD_BACKEND_URL = backendUrl;
22807
22903
  const home = overlordHome?.trim() || process.env.OVLD_HOME?.trim();
@@ -22848,7 +22944,7 @@ ${envEntries}
22848
22944
  <key>StandardErrorPath</key>
22849
22945
  <string>${xmlEscape(path33.join(logDir, "runner-service.err.log"))}</string>
22850
22946
  <key>ProcessType</key>
22851
- <string>Background</string>
22947
+ <string>${LAUNCHD_PROCESS_TYPE}</string>
22852
22948
  </dict>
22853
22949
  </plist>
22854
22950
  `;
@@ -22913,7 +23009,7 @@ function resolveServiceManager(platform2 = process.platform) {
22913
23009
  if (platform2 === "linux") return new SystemdUserManager();
22914
23010
  return null;
22915
23011
  }
22916
- var execFileAsync, RUNNER_SERVICE_STATE_FILENAME, LAUNCHD_LABEL, SYSTEMD_UNIT_NAME, FALLBACK_POLL_INTERVAL_MS, LaunchdManager, SystemdUserManager;
23012
+ var execFileAsync, RUNNER_SERVICE_STATE_FILENAME, LAUNCHD_LABEL, SYSTEMD_UNIT_NAME, FALLBACK_POLL_INTERVAL_MS, LAUNCHD_PROCESS_TYPE, RUNNER_SERVICE_SYSTEM_PATH_DIRS, RUNNER_SERVICE_PATH_PREFIX_DIRS, LaunchdManager, SystemdUserManager;
22917
23013
  var init_runner_service = __esm({
22918
23014
  "src/runner-service.ts"() {
22919
23015
  "use strict";
@@ -22923,6 +23019,9 @@ var init_runner_service = __esm({
22923
23019
  LAUNCHD_LABEL = "io.overlord.runner";
22924
23020
  SYSTEMD_UNIT_NAME = "overlord-runner";
22925
23021
  FALLBACK_POLL_INTERVAL_MS = 5e3;
23022
+ LAUNCHD_PROCESS_TYPE = "Interactive";
23023
+ RUNNER_SERVICE_SYSTEM_PATH_DIRS = ["/usr/bin", "/bin", "/usr/sbin", "/sbin"];
23024
+ RUNNER_SERVICE_PATH_PREFIX_DIRS = ["/opt/homebrew/bin", "/usr/local/bin"];
22926
23025
  LaunchdManager = class {
22927
23026
  kind = "launchd";
22928
23027
  identifier = LAUNCHD_LABEL;
@@ -24821,7 +24920,14 @@ async function runRunnerServiceCommand({
24821
24920
  const runState = await manager.status();
24822
24921
  const state = readRunnerServiceState();
24823
24922
  const publisher = process.platform !== "darwin" || !state.execProgram ? "unknown" : state.execProgram.includes(".app/Contents/MacOS/") ? "overlord" : "node";
24824
- const reinstallHint = runState.installed && publisher === "node" ? 'This service is registered under "Node.js Foundation" because it runs the plain node binary. Reinstall it from the Overlord desktop app (or with the desktop app present) to re-register it under "Overlord".' : null;
24923
+ const inspected = manager.kind === "launchd" && runState.installed ? inspectInstalledLaunchdPlist(manager.unitPath()) : null;
24924
+ const processType = inspected?.processType ?? null;
24925
+ const reinstallHint = runnerServiceReinstallHint({
24926
+ installed: runState.installed,
24927
+ publisher,
24928
+ processType,
24929
+ ...inspected ? { path: inspected.path } : {}
24930
+ });
24825
24931
  const payload = {
24826
24932
  supported: true,
24827
24933
  kind: manager.kind,
@@ -24837,6 +24943,8 @@ async function runRunnerServiceCommand({
24837
24943
  lastError: state.lastError,
24838
24944
  currentPollIntervalMs: state.currentPollIntervalMs,
24839
24945
  publisher,
24946
+ processType,
24947
+ path: inspected?.path ?? null,
24840
24948
  reinstallHint
24841
24949
  };
24842
24950
  if (json) printJson(payload);
@@ -24846,6 +24954,7 @@ async function runRunnerServiceCommand({
24846
24954
  Installed: runState.installed ? "yes" : "no",
24847
24955
  Running: runState.running,
24848
24956
  Publisher: publisher === "unknown" ? "(unknown)" : publisher,
24957
+ ...processType ? { "Process type": processType } : {},
24849
24958
  Backend: state.backendUrl ?? "(unknown)",
24850
24959
  "Last heartbeat": state.lastHeartbeatAt ?? "(never)",
24851
24960
  "Last launched": state.lastLaunchedAt ?? "(never)",
@@ -24881,7 +24990,7 @@ Note: ${reinstallHint}`);
24881
24990
  if (json) printJson({ started: autoStart, ...runState });
24882
24991
  else
24883
24992
  console.log(
24884
- `Persistent runner installed (${manager.kind}) and ${autoStart ? "started" : "not started"}.`
24993
+ `Persistent runner installed (${manager.kind}) and ${autoStart ? "started" : "not started"}.` + (manager.kind === "launchd" ? " Re-running install rewrites the LaunchAgent (ProcessType Interactive and PATH prefix); app auto-update respawns the process but does not rewrite the plist." : "")
24885
24994
  );
24886
24995
  return;
24887
24996
  }