overlord-cli 0.2608131824.0 → 0.2608141252.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
@@ -63,6 +63,10 @@ var init_redact_secrets = __esm({
63
63
  });
64
64
 
65
65
  // src/errors.ts
66
+ function isUnlinkableExecutionRequestError(error) {
67
+ const message = error instanceof Error ? error.message : String(error);
68
+ return message.includes("invalid_execution_request_transition");
69
+ }
66
70
  function formatCliError(error) {
67
71
  if (error instanceof CliError) {
68
72
  return redactSecrets(error.message);
@@ -16527,12 +16531,113 @@ var init_dist2 = __esm({
16527
16531
  }
16528
16532
  });
16529
16533
 
16530
- // ../packages/core/dist/service/latch-launch.js
16534
+ // ../packages/core/dist/service/latch-environment.js
16535
+ function isUtf8Locale(value) {
16536
+ return typeof value === "string" && UTF8_LOCALE_PATTERN.test(value);
16537
+ }
16538
+ function latchChildEnvironment({ baseEnv = process.env, platform: platform2 = process.platform } = {}) {
16539
+ const effective = baseEnv.LC_ALL ?? baseEnv.LC_CTYPE ?? baseEnv.LANG;
16540
+ if (isUtf8Locale(effective))
16541
+ return { ...baseEnv };
16542
+ const env = {
16543
+ ...baseEnv,
16544
+ // macOS ships the bare `UTF-8` locale; glibc systems ship `C.UTF-8`.
16545
+ LC_CTYPE: platform2 === "darwin" ? "UTF-8" : "C.UTF-8"
16546
+ };
16547
+ if (env.LC_ALL !== void 0 && !isUtf8Locale(env.LC_ALL))
16548
+ delete env.LC_ALL;
16549
+ return env;
16550
+ }
16551
+ var UTF8_LOCALE_PATTERN;
16552
+ var init_latch_environment = __esm({
16553
+ "../packages/core/dist/service/latch-environment.js"() {
16554
+ "use strict";
16555
+ UTF8_LOCALE_PATTERN = /utf-?8/i;
16556
+ }
16557
+ });
16558
+
16559
+ // ../packages/core/dist/service/terminal-profile-types.js
16560
+ function parseViewerOpenAs(value) {
16561
+ return typeof value === "string" && value.trim().toLowerCase() === "tab" ? "tab" : DEFAULT_VIEWER_OPEN_AS;
16562
+ }
16531
16563
  function trimmed(value) {
16532
16564
  return typeof value === "string" && value.trim() ? value.trim() : null;
16533
16565
  }
16566
+ function viewerKindForLauncher(launcher) {
16567
+ const value = trimmed(launcher);
16568
+ if (!value)
16569
+ return "inline";
16570
+ const lowered = value.toLowerCase();
16571
+ if (lowered === "iterm2" || lowered === "iterm")
16572
+ return "iterm";
16573
+ if (lowered === "terminal")
16574
+ return "terminal";
16575
+ return "custom";
16576
+ }
16577
+ function normalizeExecutionProvider(value) {
16578
+ if (!value || typeof value !== "object" || Array.isArray(value))
16579
+ return null;
16580
+ const cast = value;
16581
+ const kind = trimmed(cast.kind)?.toLowerCase() === "latch" ? "latch" : "direct";
16582
+ return {
16583
+ kind,
16584
+ executable: trimmed(cast.executable) ?? DEFAULT_LATCH_EXECUTABLE
16585
+ };
16586
+ }
16587
+ function launchSessionSnapshotFromMetadata(metadata) {
16588
+ const raw = metadata?.[LAUNCH_SESSION_METADATA_KEY];
16589
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
16590
+ return null;
16591
+ const cast = raw;
16592
+ if (cast.version !== TERMINAL_PROFILE_VERSION)
16593
+ return null;
16594
+ const viewer = cast.viewer && typeof cast.viewer === "object" && !Array.isArray(cast.viewer) ? cast.viewer : null;
16595
+ const launcher = trimmed(viewer?.launcher);
16596
+ const source = (value) => trimmed(value) === "target" ? "target" : "user_default";
16597
+ return {
16598
+ version: TERMINAL_PROFILE_VERSION,
16599
+ executionProvider: normalizeExecutionProvider(cast.executionProvider) ?? {
16600
+ ...DEFAULT_EXECUTION_PROVIDER
16601
+ },
16602
+ viewer: {
16603
+ kind: trimmed(viewer?.kind) ? trimmed(viewer?.kind) : viewerKindForLauncher(launcher),
16604
+ launcher,
16605
+ openOnLaunch: viewer?.openOnLaunch !== false,
16606
+ // A snapshot frozen before `openAs` existed carries none; `window` is what
16607
+ // those runs actually did, so the absent case must not become `tab`.
16608
+ openAs: parseViewerOpenAs(viewer?.openAs)
16609
+ },
16610
+ executionProviderSource: source(cast.executionProviderSource),
16611
+ viewerOpenSource: source(cast.viewerOpenSource),
16612
+ resolvedAt: trimmed(cast.resolvedAt) ?? ""
16613
+ };
16614
+ }
16615
+ var DEFAULT_VIEWER_OPEN_AS, TERMINAL_PROFILE_VERSION, DEFAULT_LATCH_EXECUTABLE, DEFAULT_EXECUTION_PROVIDER, DEFAULT_OPEN_VIEWER_ON_LAUNCH, DEFAULT_LAUNCH_SESSION_DEFAULTS, LAUNCH_SESSION_METADATA_KEY;
16616
+ var init_terminal_profile_types2 = __esm({
16617
+ "../packages/core/dist/service/terminal-profile-types.js"() {
16618
+ "use strict";
16619
+ DEFAULT_VIEWER_OPEN_AS = "window";
16620
+ TERMINAL_PROFILE_VERSION = 1;
16621
+ DEFAULT_LATCH_EXECUTABLE = "latch";
16622
+ DEFAULT_EXECUTION_PROVIDER = {
16623
+ kind: "direct",
16624
+ executable: DEFAULT_LATCH_EXECUTABLE
16625
+ };
16626
+ DEFAULT_OPEN_VIEWER_ON_LAUNCH = true;
16627
+ DEFAULT_LAUNCH_SESSION_DEFAULTS = {
16628
+ executionProvider: { ...DEFAULT_EXECUTION_PROVIDER },
16629
+ openViewerOnLaunch: DEFAULT_OPEN_VIEWER_ON_LAUNCH
16630
+ };
16631
+ LAUNCH_SESSION_METADATA_KEY = "launchSession";
16632
+ }
16633
+ });
16634
+
16635
+ // ../packages/core/dist/service/latch-launch.js
16636
+ function trimmed2(value) {
16637
+ return typeof value === "string" && value.trim() ? value.trim() : null;
16638
+ }
16534
16639
  function buildLatchCreateManifest({ commandString, shell = process.env.SHELL?.trim() || "/bin/bash", cwd, env, size = DEFAULT_LATCH_TERMINAL_SIZE, title, name, commandLabel, externalRunId }) {
16535
- const shellPath = trimmed(shell) ?? "/bin/bash";
16640
+ const shellPath = trimmed2(shell) ?? "/bin/bash";
16536
16641
  const cleanedEnv = {};
16537
16642
  for (const [key, value] of Object.entries(env)) {
16538
16643
  if (key.trim() && typeof value === "string")
@@ -16541,19 +16646,19 @@ function buildLatchCreateManifest({ commandString, shell = process.env.SHELL?.tr
16541
16646
  const display = {
16542
16647
  source: {
16543
16648
  kind: "overlord",
16544
- ...trimmed(externalRunId) ? { external_run_id: trimmed(externalRunId) } : {}
16649
+ ...trimmed2(externalRunId) ? { external_run_id: trimmed2(externalRunId) } : {}
16545
16650
  }
16546
16651
  };
16547
- if (trimmed(title))
16548
- display.title = trimmed(title);
16549
- if (trimmed(name))
16550
- display.name = trimmed(name);
16551
- if (trimmed(commandLabel))
16552
- display.command_label = trimmed(commandLabel);
16652
+ if (trimmed2(title))
16653
+ display.title = trimmed2(title);
16654
+ if (trimmed2(name))
16655
+ display.name = trimmed2(name);
16656
+ if (trimmed2(commandLabel))
16657
+ display.command_label = trimmed2(commandLabel);
16553
16658
  return {
16554
16659
  format_version: LATCH_MANIFEST_FORMAT_VERSION,
16555
16660
  launch: {
16556
- argv: [shellPath, "-lc", commandString],
16661
+ argv: [shellPath, "-ilc", commandString],
16557
16662
  cwd,
16558
16663
  env: cleanedEnv,
16559
16664
  inherit_env: true,
@@ -16568,7 +16673,7 @@ function buildLatchCreateManifest({ commandString, shell = process.env.SHELL?.tr
16568
16673
  function parseLatchCreateReport(raw) {
16569
16674
  try {
16570
16675
  const parsed = JSON.parse(raw);
16571
- const id = trimmed(parsed.session?.id);
16676
+ const id = trimmed2(parsed.session?.id);
16572
16677
  if (!id)
16573
16678
  return null;
16574
16679
  const protocolVersion = typeof parsed.protocolVersion === "number" && Number.isFinite(parsed.protocolVersion) ? parsed.protocolVersion : LATCH_MANIFEST_FORMAT_VERSION;
@@ -16576,9 +16681,9 @@ function parseLatchCreateReport(raw) {
16576
16681
  protocolVersion,
16577
16682
  session: {
16578
16683
  id,
16579
- name: trimmed(parsed.session?.name) ?? id,
16580
- state: trimmed(parsed.session?.state) ?? "running",
16581
- createdAt: trimmed(parsed.session?.createdAt) ?? (/* @__PURE__ */ new Date()).toISOString()
16684
+ name: trimmed2(parsed.session?.name) ?? id,
16685
+ state: trimmed2(parsed.session?.state) ?? "running",
16686
+ createdAt: trimmed2(parsed.session?.createdAt) ?? (/* @__PURE__ */ new Date()).toISOString()
16582
16687
  }
16583
16688
  };
16584
16689
  } catch {
@@ -16590,28 +16695,28 @@ function toExecutionProviderSession({ createReport, executionTargetId, createdAt
16590
16695
  provider: "latch",
16591
16696
  providerSessionId: createReport.session.id,
16592
16697
  sessionName: createReport.session.name,
16593
- executionTargetId: trimmed(executionTargetId),
16698
+ executionTargetId: trimmed2(executionTargetId),
16594
16699
  agentSessionId: null,
16595
16700
  createdAt: createdAt ?? createReport.session.createdAt,
16596
16701
  lastObservedState: createReport.session.state
16597
16702
  };
16598
16703
  }
16599
16704
  function existingLatchProviderSession({ latchSessionId, executionTargetId, createdAt = (/* @__PURE__ */ new Date()).toISOString() }) {
16600
- const providerSessionId = trimmed(latchSessionId);
16705
+ const providerSessionId = trimmed2(latchSessionId);
16601
16706
  if (!providerSessionId)
16602
16707
  return null;
16603
16708
  return {
16604
16709
  provider: "latch",
16605
16710
  providerSessionId,
16606
16711
  sessionName: null,
16607
- executionTargetId: trimmed(executionTargetId),
16712
+ executionTargetId: trimmed2(executionTargetId),
16608
16713
  agentSessionId: null,
16609
16714
  createdAt,
16610
16715
  lastObservedState: "running"
16611
16716
  };
16612
16717
  }
16613
16718
  function latchViewerFlagForKind(kind) {
16614
- switch (trimmed(kind)?.toLowerCase()) {
16719
+ switch (trimmed2(kind)?.toLowerCase()) {
16615
16720
  case "iterm":
16616
16721
  case "iterm2":
16617
16722
  return "iterm";
@@ -16619,28 +16724,59 @@ function latchViewerFlagForKind(kind) {
16619
16724
  return null;
16620
16725
  }
16621
16726
  }
16727
+ function compareLatchProductVersions(a, b) {
16728
+ const parts = (value) => value.trim().split(".").map((segment) => {
16729
+ const parsed = Number.parseInt(segment, 10);
16730
+ return Number.isFinite(parsed) ? parsed : 0;
16731
+ });
16732
+ const left = parts(a);
16733
+ const right = parts(b);
16734
+ const length = Math.max(left.length, right.length);
16735
+ for (let index = 0; index < length; index += 1) {
16736
+ const diff = (left[index] ?? 0) - (right[index] ?? 0);
16737
+ if (diff !== 0)
16738
+ return diff;
16739
+ }
16740
+ return 0;
16741
+ }
16742
+ function latchSupportsOpenAs(productVersion) {
16743
+ const version = trimmed2(productVersion);
16744
+ if (!version)
16745
+ return false;
16746
+ return compareLatchProductVersions(version, LATCH_OPEN_AS_MIN_PRODUCT_VERSION) >= 0;
16747
+ }
16748
+ function buildLatchOpenArgs({ providerSessionId, viewer, openAs, productVersion }) {
16749
+ const args = ["open", providerSessionId, "--with", viewer];
16750
+ if (openAs && latchSupportsOpenAs(productVersion)) {
16751
+ args.push("--as", parseViewerOpenAs(openAs));
16752
+ }
16753
+ args.push("--json");
16754
+ return args;
16755
+ }
16622
16756
  function latchAttachCommand({ executable = "latch", providerSessionId }) {
16623
- return `${trimmed(executable) ?? "latch"} attach ${providerSessionId}`;
16757
+ return `${trimmed2(executable) ?? "latch"} attach ${providerSessionId}`;
16624
16758
  }
16625
16759
  function shouldUseLatchProvider({ providerKind, latchSelectable }) {
16626
- return trimmed(providerKind)?.toLowerCase() === "latch" && latchSelectable === true;
16760
+ return trimmed2(providerKind)?.toLowerCase() === "latch" && latchSelectable === true;
16627
16761
  }
16628
- var LATCH_MANIFEST_FORMAT_VERSION, DEFAULT_LATCH_TERMINAL_SIZE;
16762
+ var LATCH_MANIFEST_FORMAT_VERSION, DEFAULT_LATCH_TERMINAL_SIZE, LATCH_OPEN_AS_MIN_PRODUCT_VERSION;
16629
16763
  var init_latch_launch = __esm({
16630
16764
  "../packages/core/dist/service/latch-launch.js"() {
16631
16765
  "use strict";
16766
+ init_terminal_profile_types2();
16632
16767
  LATCH_MANIFEST_FORMAT_VERSION = 1;
16633
16768
  DEFAULT_LATCH_TERMINAL_SIZE = { cols: 120, rows: 36 };
16769
+ LATCH_OPEN_AS_MIN_PRODUCT_VERSION = "0.2608140931.0";
16634
16770
  }
16635
16771
  });
16636
16772
 
16637
16773
  // ../packages/core/dist/service/latch-session.js
16638
16774
  import { spawnSync as spawnSync2 } from "node:child_process";
16639
- function trimmed2(value) {
16775
+ function trimmed3(value) {
16640
16776
  return typeof value === "string" && value.trim() ? value.trim() : null;
16641
16777
  }
16642
16778
  function parseState(value) {
16643
- switch (trimmed2(value)) {
16779
+ switch (trimmed3(value)) {
16644
16780
  case "running":
16645
16781
  return "running";
16646
16782
  case "exited":
@@ -16658,7 +16794,8 @@ function runLatchJson({ executable, args }) {
16658
16794
  encoding: "utf8",
16659
16795
  shell: false,
16660
16796
  timeout: 1e4,
16661
- maxBuffer: 1024 * 1024
16797
+ maxBuffer: 1024 * 1024,
16798
+ env: latchChildEnvironment()
16662
16799
  });
16663
16800
  if (result.error) {
16664
16801
  throw new LatchSessionCommandError(result.error.message);
@@ -16678,11 +16815,11 @@ function runLatchJson({ executable, args }) {
16678
16815
  }
16679
16816
  }
16680
16817
  function inspectLatchSession({ executable = "latch", providerSessionId }) {
16681
- const sessionId = trimmed2(providerSessionId);
16818
+ const sessionId = trimmed3(providerSessionId);
16682
16819
  if (!sessionId)
16683
16820
  throw new LatchSessionCommandError("A Latch session id is required.");
16684
16821
  const report = runLatchJson({
16685
- executable: trimmed2(executable) ?? "latch",
16822
+ executable: trimmed3(executable) ?? "latch",
16686
16823
  args: ["inspect", sessionId, "--json"]
16687
16824
  });
16688
16825
  const state = parseState(report.state);
@@ -16690,47 +16827,61 @@ function inspectLatchSession({ executable = "latch", providerSessionId }) {
16690
16827
  throw new LatchSessionCommandError("Latch returned an unsupported session state.");
16691
16828
  const exit = report.exit && typeof report.exit === "object" && !Array.isArray(report.exit) ? report.exit : null;
16692
16829
  return {
16693
- providerSessionId: trimmed2(report.id) ?? sessionId,
16694
- name: trimmed2(report.name) ?? sessionId,
16830
+ providerSessionId: trimmed3(report.id) ?? sessionId,
16831
+ name: trimmed3(report.name) ?? sessionId,
16695
16832
  state,
16696
16833
  exitCode: typeof exit?.code === "number" && Number.isFinite(exit.code) ? exit.code : null,
16697
16834
  inspectedAt: (/* @__PURE__ */ new Date()).toISOString()
16698
16835
  };
16699
16836
  }
16700
- function openLatchSession({ executable = "latch", providerSessionId, viewerKind }) {
16701
- const sessionId = trimmed2(providerSessionId);
16837
+ function readLatchProductVersion(executable) {
16838
+ try {
16839
+ return trimmed3(runLatchJson({ executable, args: ["capabilities", "--json"] }).productVersion);
16840
+ } catch {
16841
+ return null;
16842
+ }
16843
+ }
16844
+ function openLatchSession({ executable = "latch", providerSessionId, viewerKind, openAs }) {
16845
+ const sessionId = trimmed3(providerSessionId);
16702
16846
  if (!sessionId)
16703
16847
  throw new LatchSessionCommandError("A Latch session id is required.");
16704
16848
  const viewer = latchViewerFlagForKind(viewerKind);
16705
16849
  if (!viewer) {
16706
16850
  throw new LatchSessionCommandError(`Latch cannot open the configured viewer "${viewerKind}".`);
16707
16851
  }
16852
+ const exe = trimmed3(executable) ?? "latch";
16708
16853
  const report = runLatchJson({
16709
- executable: trimmed2(executable) ?? "latch",
16710
- args: ["open", sessionId, "--with", viewer, "--json"]
16854
+ executable: exe,
16855
+ args: buildLatchOpenArgs({
16856
+ providerSessionId: sessionId,
16857
+ viewer,
16858
+ openAs,
16859
+ productVersion: openAs ? readLatchProductVersion(exe) : null
16860
+ })
16711
16861
  });
16712
16862
  if (report.opened !== true) {
16713
16863
  throw new LatchSessionCommandError(`Latch did not open the ${viewer} viewer.`);
16714
16864
  }
16715
16865
  return {
16716
- providerSessionId: trimmed2(report.id) ?? sessionId,
16717
- viewer: trimmed2(report.viewer) ?? viewer,
16718
- opened: true
16866
+ providerSessionId: trimmed3(report.id) ?? sessionId,
16867
+ viewer: trimmed3(report.viewer) ?? viewer,
16868
+ opened: true,
16869
+ behavior: trimmed3(report.behavior) ? parseViewerOpenAs(report.behavior) : null
16719
16870
  };
16720
16871
  }
16721
16872
  function stopLatchSession({ executable = "latch", providerSessionId }) {
16722
- const sessionId = trimmed2(providerSessionId);
16873
+ const sessionId = trimmed3(providerSessionId);
16723
16874
  if (!sessionId)
16724
16875
  throw new LatchSessionCommandError("A Latch session id is required.");
16725
16876
  const report = runLatchJson({
16726
- executable: trimmed2(executable) ?? "latch",
16877
+ executable: trimmed3(executable) ?? "latch",
16727
16878
  args: ["stop", sessionId, "--json"]
16728
16879
  });
16729
16880
  const state = parseState(report.state);
16730
16881
  if (!state)
16731
16882
  throw new LatchSessionCommandError("Latch returned an unsupported session state.");
16732
16883
  return {
16733
- providerSessionId: trimmed2(report.id) ?? sessionId,
16884
+ providerSessionId: trimmed3(report.id) ?? sessionId,
16734
16885
  state
16735
16886
  };
16736
16887
  }
@@ -16738,7 +16889,9 @@ var LatchSessionCommandError;
16738
16889
  var init_latch_session = __esm({
16739
16890
  "../packages/core/dist/service/latch-session.js"() {
16740
16891
  "use strict";
16892
+ init_latch_environment();
16741
16893
  init_latch_launch();
16894
+ init_terminal_profile_types2();
16742
16895
  LatchSessionCommandError = class extends Error {
16743
16896
  constructor(message) {
16744
16897
  super(message);
@@ -16750,17 +16903,17 @@ var init_latch_session = __esm({
16750
16903
 
16751
16904
  // ../packages/core/dist/service/latch-events.js
16752
16905
  import { spawn as spawn3 } from "node:child_process";
16753
- function trimmed3(value) {
16906
+ function trimmed4(value) {
16754
16907
  return typeof value === "string" && value.trim() ? value.trim() : null;
16755
16908
  }
16756
16909
  function parseHarnessEvent(value) {
16757
16910
  if (!value || typeof value !== "object" || Array.isArray(value))
16758
16911
  return null;
16759
16912
  const row = value;
16760
- const type = trimmed3(row.type);
16761
- const sessionId = trimmed3(row.sessionId);
16762
- const at = trimmed3(row.at);
16763
- const harnessVersion = trimmed3(row.harnessVersion);
16913
+ const type = trimmed4(row.type);
16914
+ const sessionId = trimmed4(row.sessionId);
16915
+ const at = trimmed4(row.at);
16916
+ const harnessVersion = trimmed4(row.harnessVersion);
16764
16917
  const connectorEpoch = typeof row.connectorEpoch === "number" && Number.isFinite(row.connectorEpoch) ? row.connectorEpoch : null;
16765
16918
  if (!type || !HARNESS_EVENT_TYPES.has(type) || !sessionId || !at || !harnessVersion)
16766
16919
  return null;
@@ -16771,26 +16924,26 @@ function parseHarnessEvent(value) {
16771
16924
  case "user_message":
16772
16925
  case "assistant_delta":
16773
16926
  case "assistant_message": {
16774
- const text = trimmed3(row.text);
16927
+ const text = trimmed4(row.text);
16775
16928
  if (!text)
16776
16929
  return null;
16777
16930
  return { ...base, type, text };
16778
16931
  }
16779
16932
  case "tool_started": {
16780
- const tool = trimmed3(row.tool);
16933
+ const tool = trimmed4(row.tool);
16781
16934
  if (!tool)
16782
16935
  return null;
16783
16936
  return { ...base, type, tool, input: row.input };
16784
16937
  }
16785
16938
  case "tool_finished": {
16786
- const tool = trimmed3(row.tool);
16939
+ const tool = trimmed4(row.tool);
16787
16940
  if (!tool)
16788
16941
  return null;
16789
16942
  return { ...base, type, tool, output: row.output };
16790
16943
  }
16791
16944
  case "awaiting_input": {
16792
- const requestId = trimmed3(row.requestId);
16793
- const kind = trimmed3(row.kind);
16945
+ const requestId = trimmed4(row.requestId);
16946
+ const kind = trimmed4(row.kind);
16794
16947
  const prompt = typeof row.prompt === "string" ? row.prompt : null;
16795
16948
  if (!requestId || kind !== "permission" && kind !== "question" || prompt === null) {
16796
16949
  return null;
@@ -16806,7 +16959,7 @@ function parseHarnessEvent(value) {
16806
16959
  };
16807
16960
  }
16808
16961
  case "status": {
16809
- const status = trimmed3(row.status);
16962
+ const status = trimmed4(row.status);
16810
16963
  if (!status)
16811
16964
  return null;
16812
16965
  return { ...base, type, status };
@@ -16831,14 +16984,15 @@ function parseHarnessEventNdjson(raw) {
16831
16984
  return events;
16832
16985
  }
16833
16986
  async function collectLatchEvents({ executable = "latch", providerSessionId, from = 0, idleMs = 250, timeoutMs = 8e3 }) {
16834
- const sessionId = trimmed3(providerSessionId);
16987
+ const sessionId = trimmed4(providerSessionId);
16835
16988
  if (!sessionId)
16836
16989
  throw new LatchSessionCommandError("A Latch session id is required.");
16837
16990
  const fromCursor = Number.isFinite(from) && from > 0 ? Math.floor(from) : 0;
16838
- const bin = trimmed3(executable) ?? "latch";
16991
+ const bin = trimmed4(executable) ?? "latch";
16839
16992
  return new Promise((resolve, reject) => {
16840
16993
  const child = spawn3(bin, ["events", sessionId, "--json", "--from", String(fromCursor)], {
16841
- stdio: ["ignore", "pipe", "pipe"]
16994
+ stdio: ["ignore", "pipe", "pipe"],
16995
+ env: latchChildEnvironment()
16842
16996
  });
16843
16997
  let stdout = "";
16844
16998
  let stderr = "";
@@ -16894,7 +17048,7 @@ async function collectLatchEvents({ executable = "latch", providerSessionId, fro
16894
17048
  finish({ ended: true, error: new LatchSessionCommandError(detail) });
16895
17049
  return;
16896
17050
  }
16897
- finish({ ended: signal == null && (code === 0 || code === null) });
17051
+ finish({ ended: signal === null && (code === 0 || code === null) });
16898
17052
  });
16899
17053
  });
16900
17054
  }
@@ -16902,6 +17056,7 @@ var HARNESS_EVENT_TYPES;
16902
17056
  var init_latch_events = __esm({
16903
17057
  "../packages/core/dist/service/latch-events.js"() {
16904
17058
  "use strict";
17059
+ init_latch_environment();
16905
17060
  init_latch_session();
16906
17061
  HARNESS_EVENT_TYPES = /* @__PURE__ */ new Set([
16907
17062
  "user_message",
@@ -17248,75 +17403,6 @@ var init_git_tree = __esm({
17248
17403
  }
17249
17404
  });
17250
17405
 
17251
- // ../packages/core/dist/service/terminal-profile-types.js
17252
- function trimmed4(value) {
17253
- return typeof value === "string" && value.trim() ? value.trim() : null;
17254
- }
17255
- function viewerKindForLauncher(launcher) {
17256
- const value = trimmed4(launcher);
17257
- if (!value)
17258
- return "inline";
17259
- const lowered = value.toLowerCase();
17260
- if (lowered === "iterm2" || lowered === "iterm")
17261
- return "iterm";
17262
- if (lowered === "terminal")
17263
- return "terminal";
17264
- return "custom";
17265
- }
17266
- function normalizeExecutionProvider(value) {
17267
- if (!value || typeof value !== "object" || Array.isArray(value))
17268
- return null;
17269
- const cast = value;
17270
- const kind = trimmed4(cast.kind)?.toLowerCase() === "latch" ? "latch" : "direct";
17271
- return {
17272
- kind,
17273
- executable: trimmed4(cast.executable) ?? DEFAULT_LATCH_EXECUTABLE
17274
- };
17275
- }
17276
- function launchSessionSnapshotFromMetadata(metadata) {
17277
- const raw = metadata?.[LAUNCH_SESSION_METADATA_KEY];
17278
- if (!raw || typeof raw !== "object" || Array.isArray(raw))
17279
- return null;
17280
- const cast = raw;
17281
- if (cast.version !== TERMINAL_PROFILE_VERSION)
17282
- return null;
17283
- const viewer = cast.viewer && typeof cast.viewer === "object" && !Array.isArray(cast.viewer) ? cast.viewer : null;
17284
- const launcher = trimmed4(viewer?.launcher);
17285
- const source = (value) => trimmed4(value) === "target" ? "target" : "user_default";
17286
- return {
17287
- version: TERMINAL_PROFILE_VERSION,
17288
- executionProvider: normalizeExecutionProvider(cast.executionProvider) ?? {
17289
- ...DEFAULT_EXECUTION_PROVIDER
17290
- },
17291
- viewer: {
17292
- kind: trimmed4(viewer?.kind) ? trimmed4(viewer?.kind) : viewerKindForLauncher(launcher),
17293
- launcher,
17294
- openOnLaunch: viewer?.openOnLaunch !== false
17295
- },
17296
- executionProviderSource: source(cast.executionProviderSource),
17297
- viewerOpenSource: source(cast.viewerOpenSource),
17298
- resolvedAt: trimmed4(cast.resolvedAt) ?? ""
17299
- };
17300
- }
17301
- var TERMINAL_PROFILE_VERSION, DEFAULT_LATCH_EXECUTABLE, DEFAULT_EXECUTION_PROVIDER, DEFAULT_OPEN_VIEWER_ON_LAUNCH, DEFAULT_LAUNCH_SESSION_DEFAULTS, LAUNCH_SESSION_METADATA_KEY;
17302
- var init_terminal_profile_types2 = __esm({
17303
- "../packages/core/dist/service/terminal-profile-types.js"() {
17304
- "use strict";
17305
- TERMINAL_PROFILE_VERSION = 1;
17306
- DEFAULT_LATCH_EXECUTABLE = "latch";
17307
- DEFAULT_EXECUTION_PROVIDER = {
17308
- kind: "direct",
17309
- executable: DEFAULT_LATCH_EXECUTABLE
17310
- };
17311
- DEFAULT_OPEN_VIEWER_ON_LAUNCH = true;
17312
- DEFAULT_LAUNCH_SESSION_DEFAULTS = {
17313
- executionProvider: { ...DEFAULT_EXECUTION_PROVIDER },
17314
- openViewerOnLaunch: DEFAULT_OPEN_VIEWER_ON_LAUNCH
17315
- };
17316
- LAUNCH_SESSION_METADATA_KEY = "launchSession";
17317
- }
17318
- });
17319
-
17320
17406
  // ../packages/core/dist/service/latch-discovery.js
17321
17407
  import { execFileSync as execFileSync3 } from "node:child_process";
17322
17408
  import { existsSync as existsSync16, mkdirSync as mkdirSync9, readFileSync as readFileSync15, statSync as statSync4, writeFileSync as writeFileSync8 } from "node:fs";
@@ -17547,6 +17633,7 @@ var SUPPORTED_LATCH_PROTOCOL_VERSION, REQUIRED_LATCH_CAPABILITIES, LATCH_STANDAL
17547
17633
  var init_latch_discovery = __esm({
17548
17634
  "../packages/core/dist/service/latch-discovery.js"() {
17549
17635
  "use strict";
17636
+ init_latch_environment();
17550
17637
  init_terminal_profile_types2();
17551
17638
  SUPPORTED_LATCH_PROTOCOL_VERSION = 1;
17552
17639
  REQUIRED_LATCH_CAPABILITIES = ["create"];
@@ -17557,7 +17644,8 @@ var init_latch_discovery = __esm({
17557
17644
  const stdout = execFileSync3(executable, argv, {
17558
17645
  encoding: "utf8",
17559
17646
  stdio: ["ignore", "pipe", "pipe"],
17560
- timeout: 5e3
17647
+ timeout: 5e3,
17648
+ env: latchChildEnvironment()
17561
17649
  });
17562
17650
  return { status: 0, stdout: String(stdout), stderr: "" };
17563
17651
  } catch (error) {
@@ -17594,7 +17682,8 @@ function probeLatchInteractionCapabilities({ executable = "latch", providerSessi
17594
17682
  const help = spawnSync3(bin, ["send", "--help"], {
17595
17683
  encoding: "utf8",
17596
17684
  shell: false,
17597
- timeout: 5e3
17685
+ timeout: 5e3,
17686
+ env: latchChildEnvironment()
17598
17687
  });
17599
17688
  if (help.error || help.status !== 0) {
17600
17689
  const detail = (help.stderr || help.stdout || help.error?.message || "latch send is unavailable").trim().slice(0, 200);
@@ -17637,7 +17726,8 @@ function resolveLatchInput({ executable = "latch", providerSessionId, requestId,
17637
17726
  encoding: "utf8",
17638
17727
  shell: false,
17639
17728
  timeout: 1e4,
17640
- maxBuffer: 1024 * 1024
17729
+ maxBuffer: 1024 * 1024,
17730
+ env: latchChildEnvironment()
17641
17731
  });
17642
17732
  if (result.error)
17643
17733
  throw new LatchSessionCommandError(result.error.message);
@@ -17655,6 +17745,7 @@ function resolveLatchInput({ executable = "latch", providerSessionId, requestId,
17655
17745
  var init_latch_send = __esm({
17656
17746
  "../packages/core/dist/service/latch-send.js"() {
17657
17747
  "use strict";
17748
+ init_latch_environment();
17658
17749
  init_latch_session();
17659
17750
  }
17660
17751
  });
@@ -19089,7 +19180,7 @@ function spawnLatchJson({
19089
19180
  const result = spawnSync4(executable, args, {
19090
19181
  encoding: "utf8",
19091
19182
  input: stdin,
19092
- env: process.env,
19183
+ env: latchChildEnvironment(),
19093
19184
  maxBuffer: 2 * 1024 * 1024
19094
19185
  });
19095
19186
  return {
@@ -19148,7 +19239,9 @@ function createLatchSession({
19148
19239
  function openLatchViewer({
19149
19240
  executable = DEFAULT_LATCH_EXECUTABLE,
19150
19241
  providerSessionId,
19151
- viewerKind
19242
+ viewerKind,
19243
+ openAs,
19244
+ productVersion
19152
19245
  }) {
19153
19246
  const viewer = latchViewerFlagForKind(viewerKind);
19154
19247
  const attachCommand = latchAttachCommand({ executable, providerSessionId });
@@ -19159,9 +19252,10 @@ function openLatchViewer({
19159
19252
  attachCommand
19160
19253
  };
19161
19254
  }
19255
+ const sendsOpenAs = Boolean(openAs) && latchSupportsOpenAs(productVersion);
19162
19256
  const result = spawnLatchJson({
19163
19257
  executable,
19164
- args: ["open", providerSessionId, "--with", viewer, "--json"]
19258
+ args: buildLatchOpenArgs({ providerSessionId, viewer, openAs, productVersion })
19165
19259
  });
19166
19260
  if (result.status !== 0) {
19167
19261
  const detail = (result.stderr || result.stdout || `exit ${result.status ?? "null"}`).trim();
@@ -19171,11 +19265,12 @@ function openLatchViewer({
19171
19265
  attachCommand
19172
19266
  };
19173
19267
  }
19174
- return { ok: true, viewer };
19268
+ return { ok: true, viewer, openAs: sendsOpenAs ? parseViewerOpenAs(openAs) : null };
19175
19269
  }
19176
19270
  var init_latch_launch2 = __esm({
19177
19271
  "src/latch-launch.ts"() {
19178
19272
  "use strict";
19273
+ init_latch_environment();
19179
19274
  init_latch_launch();
19180
19275
  init_terminal_profile_types2();
19181
19276
  }
@@ -19878,13 +19973,14 @@ async function launchAgent({
19878
19973
  let providerFallbackWarning = null;
19879
19974
  let useLatch = false;
19880
19975
  let resolvedLatchExecutable = executable;
19976
+ let latchProductVersion = null;
19881
19977
  const existingProviderSession = providerKind === "latch" ? existingLatchProviderSession({
19882
19978
  latchSessionId: process.env.LATCH_SESSION_ID,
19883
19979
  executionTargetId: options.executionTargetId
19884
19980
  }) : null;
19885
19981
  if (existingProviderSession && plan.latchCommandString) {
19886
19982
  const shell = process.env.SHELL?.trim() || "/bin/bash";
19887
- const result2 = spawnSync5(shell, ["-lc", plan.latchCommandString], {
19983
+ const result2 = spawnSync5(shell, ["-ilc", plan.latchCommandString], {
19888
19984
  cwd: options.workingDirectory,
19889
19985
  env,
19890
19986
  stdio: "inherit"
@@ -19894,7 +19990,7 @@ async function launchAgent({
19894
19990
  ...plan,
19895
19991
  execution: {
19896
19992
  command: shell,
19897
- args: ["-lc", plan.latchCommandString],
19993
+ args: ["-ilc", plan.latchCommandString],
19898
19994
  useShell: false,
19899
19995
  terminal: null,
19900
19996
  display: `Latch session ${existingProviderSession.providerSessionId} (inline) \u203A ${plan.latchCommandString}`
@@ -19921,6 +20017,7 @@ async function launchAgent({
19921
20017
  });
19922
20018
  if (useLatch && discovery.state === "found") {
19923
20019
  resolvedLatchExecutable = discovery.resolvedPath;
20020
+ latchProductVersion = discovery.productVersion;
19924
20021
  }
19925
20022
  if (!useLatch) {
19926
20023
  providerFallbackWarning = discovery.state === "not_installed" ? `Latch is not installed on this execution target (${discovery.installCommand}); falling back to direct launch.` : discovery.state === "incompatible" ? `Latch is incompatible (${discovery.missingCapability}: ${discovery.detail}); falling back to direct launch.` : "Latch is unavailable; falling back to direct launch.";
@@ -19945,7 +20042,9 @@ async function launchAgent({
19945
20042
  viewerOpen = openLatchViewer({
19946
20043
  executable: resolvedLatchExecutable,
19947
20044
  providerSessionId: created.providerSession.providerSessionId,
19948
- viewerKind: snapshot?.viewer.kind ?? "iterm"
20045
+ viewerKind: snapshot?.viewer.kind ?? "iterm",
20046
+ openAs: snapshot?.viewer.openAs ?? null,
20047
+ productVersion: latchProductVersion
19949
20048
  });
19950
20049
  }
19951
20050
  return {
@@ -21400,6 +21499,11 @@ var init_vcs = __esm({
21400
21499
  // src/record-touched.ts
21401
21500
  import { readFileSync as readFileSync20 } from "node:fs";
21402
21501
  import path29 from "node:path";
21502
+ function firstNonEmptyString(value) {
21503
+ if (typeof value !== "string") return null;
21504
+ const trimmed7 = value.trim();
21505
+ return trimmed7 ? trimmed7 : null;
21506
+ }
21403
21507
  function collectCandidates(toolInput) {
21404
21508
  const counts = /* @__PURE__ */ new Map();
21405
21509
  const order = [];
@@ -21411,22 +21515,43 @@ function collectCandidates(toolInput) {
21411
21515
  counts.set(trimmed7, (counts.get(trimmed7) ?? 0) + amount);
21412
21516
  };
21413
21517
  bump(toolInput.file_path, 1);
21518
+ bump(toolInput.filePath, 1);
21519
+ bump(toolInput.path, 1);
21414
21520
  bump(toolInput.notebook_path, 1);
21415
21521
  const edits = toolInput.edits;
21416
21522
  if (Array.isArray(edits)) {
21417
- const topLevelPath = toolInput.file_path;
21418
- if (typeof topLevelPath === "string" && topLevelPath.trim()) {
21419
- counts.set(topLevelPath.trim(), (counts.get(topLevelPath.trim()) ?? 0) - 1);
21523
+ const topLevelPath = firstNonEmptyString(toolInput.file_path) ?? firstNonEmptyString(toolInput.filePath) ?? firstNonEmptyString(toolInput.path);
21524
+ if (topLevelPath) {
21525
+ counts.set(topLevelPath, (counts.get(topLevelPath) ?? 0) - 1);
21420
21526
  }
21421
21527
  for (const edit of edits) {
21422
21528
  if (edit && typeof edit === "object") {
21423
- const value = edit.file_path ?? topLevelPath;
21529
+ const record = edit;
21530
+ const value = record.file_path ?? record.filePath ?? record.path ?? topLevelPath;
21424
21531
  bump(value, 1);
21425
21532
  }
21426
21533
  }
21427
21534
  }
21428
21535
  return order.map((filePath) => ({ filePath, editCount: Math.max(counts.get(filePath) ?? 1, 1) }));
21429
21536
  }
21537
+ function resolveHookWorkingDirectory({
21538
+ payload,
21539
+ fallbackCwd,
21540
+ env
21541
+ }) {
21542
+ const fromCwd = firstNonEmptyString(payload.cwd);
21543
+ if (fromCwd) return path29.resolve(fromCwd);
21544
+ const roots = payload.workspace_roots;
21545
+ if (Array.isArray(roots)) {
21546
+ const fromRoots = firstNonEmptyString(roots[0]);
21547
+ if (fromRoots) return path29.resolve(fromRoots);
21548
+ }
21549
+ for (const key of PROJECT_DIR_ENV_KEYS) {
21550
+ const fromEnv = firstNonEmptyString(env[key]);
21551
+ if (fromEnv) return path29.resolve(fromEnv);
21552
+ }
21553
+ return path29.resolve(fallbackCwd);
21554
+ }
21430
21555
  function compact(value, limit = 500) {
21431
21556
  if (typeof value !== "string") return null;
21432
21557
  const text = value.split(/\s+/).filter(Boolean).join(" ");
@@ -21486,7 +21611,8 @@ function recentAssistantContext(transcriptPath) {
21486
21611
  function recordTouchedFromPayload({
21487
21612
  rawPayload,
21488
21613
  missionOverride,
21489
- fallbackCwd
21614
+ fallbackCwd,
21615
+ env = process.env
21490
21616
  }) {
21491
21617
  let payload;
21492
21618
  try {
@@ -21497,8 +21623,7 @@ function recordTouchedFromPayload({
21497
21623
  const toolInputRaw = payload.tool_input;
21498
21624
  const toolInput = toolInputRaw && typeof toolInputRaw === "object" ? toolInputRaw : {};
21499
21625
  const toolName = typeof payload.tool_name === "string" && payload.tool_name.trim() ? payload.tool_name.trim() : "file edit";
21500
- const cwd = typeof payload.cwd === "string" && payload.cwd.trim() ? payload.cwd.trim() : fallbackCwd;
21501
- const workingDirectory = path29.resolve(cwd);
21626
+ const workingDirectory = resolveHookWorkingDirectory({ payload, fallbackCwd, env });
21502
21627
  const trimmedOverride = missionOverride?.trim();
21503
21628
  let missionId;
21504
21629
  let ambiguous = false;
@@ -21507,7 +21632,10 @@ function recordTouchedFromPayload({
21507
21632
  } else {
21508
21633
  const resolved = resolveActiveMissionForCwd(workingDirectory);
21509
21634
  if (!resolved) {
21510
- return { recorded: false, reason: "no active session manifest entry for this cwd" };
21635
+ return {
21636
+ recorded: false,
21637
+ reason: `no active session manifest entry for this cwd (${workingDirectory})`
21638
+ };
21511
21639
  }
21512
21640
  missionId = resolved.missionId;
21513
21641
  ambiguous = resolved.ambiguous;
@@ -21538,11 +21666,17 @@ function recordTouchedFromPayload({
21538
21666
  });
21539
21667
  return { recorded: true, missionId, ambiguous, files: candidates.length };
21540
21668
  }
21669
+ var PROJECT_DIR_ENV_KEYS;
21541
21670
  var init_record_touched = __esm({
21542
21671
  "src/record-touched.ts"() {
21543
21672
  "use strict";
21544
21673
  init_vcs();
21545
21674
  init_vcs_sessions();
21675
+ PROJECT_DIR_ENV_KEYS = [
21676
+ "CURSOR_PROJECT_DIR",
21677
+ "CLAUDE_PROJECT_DIR",
21678
+ "CLAUDE_PROJECT_ROOT"
21679
+ ];
21546
21680
  }
21547
21681
  });
21548
21682
 
@@ -22711,10 +22845,24 @@ async function runProtocolCommand({
22711
22845
  workingDirectory
22712
22846
  })
22713
22847
  };
22714
- const result = await runtime.backend.post({
22715
- path: `/api/protocol/${encodeURIComponent(subcommand)}`,
22716
- body: protocolBody
22717
- });
22848
+ const protocolPath = `/api/protocol/${encodeURIComponent(subcommand)}`;
22849
+ let result;
22850
+ try {
22851
+ result = await runtime.backend.post({
22852
+ path: protocolPath,
22853
+ body: protocolBody
22854
+ });
22855
+ } catch (error) {
22856
+ if (subcommand === "attach" && typeof flags["--execution-request-id"] === "string" && isUnlinkableExecutionRequestError(error)) {
22857
+ delete flags["--execution-request-id"];
22858
+ result = await runtime.backend.post({
22859
+ path: protocolPath,
22860
+ body: { ...protocolBody, flags }
22861
+ });
22862
+ } else {
22863
+ throw error;
22864
+ }
22865
+ }
22718
22866
  if ((subcommand === "attach" || subcommand === "resume-follow-up") && missionId) {
22719
22867
  writeBaseline({
22720
22868
  workingDirectory,
@@ -22768,7 +22916,7 @@ async function runProtocolCommand({
22768
22916
  )
22769
22917
  );
22770
22918
  if (connectorInstallsEditHook && !hasTouchedFilesLog({ workingDirectory, missionId }) && readChangedFiles(workingDirectory).length > 0) {
22771
- const warning = `[overlord] warning: no touched-files log found at deliver for mission ${missionId} in ${workingDirectory}, even though this connector installs a PostToolUse edit hook. Deliver is falling back to baseline-only attribution, which can misattribute concurrent sessions' edits. Check ~/.ovld/logs/post-tool-use-hook.log for why the hook did not record any touched files.`;
22919
+ const warning = `[overlord] warning: no touched-files log found at deliver for mission ${missionId} in ${workingDirectory}, even though this connector installs a PostToolUse edit hook. Deliver is falling back to baseline-only attribution, which can misattribute concurrent sessions' edits. Check ~/.ovld/logs/cursor-post-tool-use-hook.log and ~/.ovld/logs/post-tool-use-hook.log for why the hook did not record any touched files.`;
22772
22920
  console.error(warning);
22773
22921
  const sessionKeyForAlert = typeof flags["--session-key"] === "string" ? flags["--session-key"] : void 0;
22774
22922
  if (sessionKeyForAlert) {