overlord-cli 0.2608120914.0 → 0.2608121828.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
@@ -262,16 +262,16 @@ function resolveCommandArgs({
262
262
  return parsed;
263
263
  }
264
264
  function normalizeVersion(raw) {
265
- const trimmed = raw.trim();
266
- if (!trimmed) {
265
+ const trimmed5 = raw.trim();
266
+ if (!trimmed5) {
267
267
  throw new CliError({ message: "Received an empty version from npm." });
268
268
  }
269
269
  try {
270
- const parsed = JSON.parse(trimmed);
270
+ const parsed = JSON.parse(trimmed5);
271
271
  if (typeof parsed === "string" && parsed.trim()) return parsed.trim();
272
272
  } catch {
273
273
  }
274
- return trimmed.replace(/^"+|"+$/g, "");
274
+ return trimmed5.replace(/^"+|"+$/g, "");
275
275
  }
276
276
  function compareVersions(left, right) {
277
277
  const leftParts = left.split(".").map((part) => Number.parseInt(part, 10));
@@ -1330,11 +1330,11 @@ import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync3, wr
1330
1330
  import os from "node:os";
1331
1331
  import path3 from "node:path";
1332
1332
  function normalizeBackendUrl(value) {
1333
- const trimmed = value.trim().replace(/\/+$/, "");
1334
- if (/^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed)) {
1335
- return trimmed;
1333
+ const trimmed5 = value.trim().replace(/\/+$/, "");
1334
+ if (/^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed5)) {
1335
+ return trimmed5;
1336
1336
  }
1337
- return `http://${trimmed}`;
1337
+ return `http://${trimmed5}`;
1338
1338
  }
1339
1339
  function isLoopbackBackendUrl(backendUrl) {
1340
1340
  try {
@@ -2396,12 +2396,12 @@ function parseConnectorManifestYaml(text) {
2396
2396
  };
2397
2397
  for (const rawLine of text.split("\n")) {
2398
2398
  const line = rawLine.replace(/\r$/, "");
2399
- const trimmed = line.trim();
2400
- if (trimmed === "" || trimmed.startsWith("#")) continue;
2399
+ const trimmed5 = line.trim();
2400
+ if (trimmed5 === "" || trimmed5.startsWith("#")) continue;
2401
2401
  const indent = line.length - line.trimStart().length;
2402
2402
  if (pending) {
2403
2403
  if (indent > pending.indent) {
2404
- const container = trimmed.startsWith("- ") ? [] : {};
2404
+ const container = trimmed5.startsWith("- ") ? [] : {};
2405
2405
  pending.parent[pending.key] = container;
2406
2406
  stack.push({ indent, container });
2407
2407
  pending = null;
@@ -2414,16 +2414,16 @@ function parseConnectorManifestYaml(text) {
2414
2414
  stack.pop();
2415
2415
  }
2416
2416
  const frame = stack[stack.length - 1];
2417
- if (trimmed.startsWith("- ")) {
2417
+ if (trimmed5.startsWith("- ")) {
2418
2418
  if (Array.isArray(frame.container)) {
2419
- frame.container.push(parseScalar(trimmed.slice(2)));
2419
+ frame.container.push(parseScalar(trimmed5.slice(2)));
2420
2420
  }
2421
2421
  continue;
2422
2422
  }
2423
- const colon = trimmed.indexOf(":");
2423
+ const colon = trimmed5.indexOf(":");
2424
2424
  if (colon < 0 || Array.isArray(frame.container)) continue;
2425
- const key = trimmed.slice(0, colon).trim();
2426
- const rest = trimmed.slice(colon + 1).trim();
2425
+ const key = trimmed5.slice(0, colon).trim();
2426
+ const rest = trimmed5.slice(colon + 1).trim();
2427
2427
  if (rest === "") {
2428
2428
  pending = { parent: frame.container, key, indent };
2429
2429
  } else {
@@ -2645,10 +2645,10 @@ ${managedBlock}
2645
2645
 
2646
2646
  ${after}`;
2647
2647
  }
2648
- const trimmed = existingContent.trimEnd();
2649
- if (!trimmed) return `${managedBlock}
2648
+ const trimmed5 = existingContent.trimEnd();
2649
+ if (!trimmed5) return `${managedBlock}
2650
2650
  `;
2651
- return `${trimmed}
2651
+ return `${trimmed5}
2652
2652
 
2653
2653
  ${managedBlock}
2654
2654
  `;
@@ -3158,12 +3158,12 @@ function createBackendClient() {
3158
3158
  const clientDevice = clientDeviceIdentity();
3159
3159
  async function request({
3160
3160
  method,
3161
- path: path32,
3161
+ path: path34,
3162
3162
  body,
3163
3163
  extraHeaders,
3164
3164
  rawBody
3165
3165
  }) {
3166
- const url = `${baseUrl}${path32.startsWith("/") ? path32 : `/${path32}`}`;
3166
+ const url = `${baseUrl}${path34.startsWith("/") ? path34 : `/${path34}`}`;
3167
3167
  const auth = resolveAuthHeaders({ baseUrl });
3168
3168
  let response;
3169
3169
  try {
@@ -3190,14 +3190,14 @@ Start the Desktop/local backend or run \`ovld config set cloud <url>\`.
3190
3190
  const payload = await readResponseJson2(response);
3191
3191
  if (!response.ok) {
3192
3192
  if (response.status === 401 && auth.headers.Authorization) {
3193
- const detail = errorMessageFromJson2(payload) ?? `Backend request failed: ${method} ${path32} (${response.status})`;
3193
+ const detail = errorMessageFromJson2(payload) ?? `Backend request failed: ${method} ${path34} (${response.status})`;
3194
3194
  throw new CliError({
3195
3195
  message: `${detail}
3196
3196
  ` + (auth.fromStored ? "Your saved credentials were rejected. Run `ovld auth login` to sign in again." : "Run `ovld auth login` or refresh your USER_TOKEN environment variable.")
3197
3197
  });
3198
3198
  }
3199
3199
  throw new CliError({
3200
- message: errorMessageFromJson2(payload) ?? `Backend request failed: ${method} ${path32} (${response.status})`
3200
+ message: errorMessageFromJson2(payload) ?? `Backend request failed: ${method} ${path34} (${response.status})`
3201
3201
  });
3202
3202
  }
3203
3203
  return payload;
@@ -3205,13 +3205,13 @@ Start the Desktop/local backend or run \`ovld config set cloud <url>\`.
3205
3205
  return {
3206
3206
  baseUrl,
3207
3207
  health: () => request({ method: "GET", path: "/api/health" }),
3208
- get: (path32) => request({ method: "GET", path: path32 }),
3209
- post: ({ path: path32, body }) => request({ method: "POST", path: path32, body }),
3210
- patch: ({ path: path32, body }) => request({ method: "PATCH", path: path32, body }),
3211
- delete: (path32) => request({ method: "DELETE", path: path32 }),
3212
- postRaw: ({ path: path32, body, contentType, filename }) => request({
3208
+ get: (path34) => request({ method: "GET", path: path34 }),
3209
+ post: ({ path: path34, body }) => request({ method: "POST", path: path34, body }),
3210
+ patch: ({ path: path34, body }) => request({ method: "PATCH", path: path34, body }),
3211
+ delete: (path34) => request({ method: "DELETE", path: path34 }),
3212
+ postRaw: ({ path: path34, body, contentType, filename }) => request({
3213
3213
  method: "POST",
3214
- path: path32,
3214
+ path: path34,
3215
3215
  rawBody: body,
3216
3216
  extraHeaders: {
3217
3217
  "Content-Type": contentType || "application/octet-stream",
@@ -5574,8 +5574,8 @@ function resolveNativeSessionId({
5574
5574
  env = process.env
5575
5575
  }) {
5576
5576
  if (explicit !== void 0) {
5577
- const trimmed = explicit.trim();
5578
- return trimmed === "null" ? null : trimmed || void 0;
5577
+ const trimmed5 = explicit.trim();
5578
+ return trimmed5 === "null" ? null : trimmed5 || void 0;
5579
5579
  }
5580
5580
  const normalizedAgent = agent.toLowerCase();
5581
5581
  if (normalizedAgent === "codex") {
@@ -6443,11 +6443,11 @@ function createChannelClient({
6443
6443
  token
6444
6444
  }) {
6445
6445
  const root = `${baseUrl.replace(/\/+$/, "")}/api/agent-session-channels/v1`;
6446
- async function request(method, path32, body, timeoutMs) {
6446
+ async function request(method, path34, body, timeoutMs) {
6447
6447
  const controller = new AbortController();
6448
6448
  const timer = setTimeout(() => controller.abort(), timeoutMs);
6449
6449
  try {
6450
- const response = await fetch(`${root}${path32}`, {
6450
+ const response = await fetch(`${root}${path34}`, {
6451
6451
  method,
6452
6452
  // The credential travels here and only here: an Authorization header on a request the
6453
6453
  // CLI itself constructs. Not in the URL, which lands in access logs; not in the body,
@@ -6473,8 +6473,8 @@ function createChannelClient({
6473
6473
  }
6474
6474
  }
6475
6475
  return {
6476
- post: (path32, body, options) => request("POST", path32, body ?? {}, options?.timeoutMs ?? DEFAULT_TIMEOUT_MS),
6477
- get: (path32, options) => request("GET", path32, void 0, options?.timeoutMs ?? DEFAULT_TIMEOUT_MS)
6476
+ post: (path34, body, options) => request("POST", path34, body ?? {}, options?.timeoutMs ?? DEFAULT_TIMEOUT_MS),
6477
+ get: (path34, options) => request("GET", path34, void 0, options?.timeoutMs ?? DEFAULT_TIMEOUT_MS)
6478
6478
  };
6479
6479
  }
6480
6480
  var DEFAULT_TIMEOUT_MS;
@@ -6573,9 +6573,9 @@ function reduceUrl(rawUrl) {
6573
6573
  try {
6574
6574
  const url = new URL(raw);
6575
6575
  const hadQuery = url.search !== "" || url.hash !== "";
6576
- const path32 = url.pathname === "/" ? "" : url.pathname;
6576
+ const path34 = url.pathname === "/" ? "" : url.pathname;
6577
6577
  return {
6578
- display: safeText(`${url.protocol}//${url.host}${path32}`).text,
6578
+ display: safeText(`${url.protocol}//${url.host}${path34}`).text,
6579
6579
  host: url.host || null,
6580
6580
  scheme: url.protocol.replace(/:$/, ""),
6581
6581
  hadQuery
@@ -6740,17 +6740,17 @@ var init_mcp = __esm({
6740
6740
  function describeRead({ input, projectRoot }) {
6741
6741
  const record = input && typeof input === "object" ? input : {};
6742
6742
  const raw = typeof record.file_path === "string" && record.file_path || typeof record.filePath === "string" && record.filePath || typeof record.path === "string" && record.path || typeof record.notebook_path === "string" && record.notebook_path || null;
6743
- const path32 = reducePath(raw, projectRoot);
6743
+ const path34 = reducePath(raw, projectRoot);
6744
6744
  const markers = [
6745
- path32?.outsideProject && "outside-project-directory",
6746
- path32?.nonAscii && "non-ascii-path"
6745
+ path34?.outsideProject && "outside-project-directory",
6746
+ path34?.nonAscii && "non-ascii-path"
6747
6747
  ];
6748
- if (path32 && /(^|\/)(\.env|\.npmrc|\.netrc|id_rsa|id_ed25519|credentials)(\.|$)/.test(path32.display)) {
6748
+ if (path34 && /(^|\/)(\.env|\.npmrc|\.netrc|id_rsa|id_ed25519|credentials)(\.|$)/.test(path34.display)) {
6749
6749
  markers.push("secret-adjacent");
6750
6750
  }
6751
6751
  return {
6752
6752
  action: "Read a file",
6753
- subject: path32?.display ?? null,
6753
+ subject: path34?.display ?? null,
6754
6754
  detail: null,
6755
6755
  riskMarkers: normalizeMarkers(markers)
6756
6756
  };
@@ -6892,21 +6892,21 @@ function isOverwrite(record) {
6892
6892
  }
6893
6893
  function describeWrite({ input, projectRoot }) {
6894
6894
  const record = input && typeof input === "object" ? input : {};
6895
- const path32 = reducePath(readPath(record), projectRoot);
6895
+ const path34 = reducePath(readPath(record), projectRoot);
6896
6896
  const overwrite = isOverwrite(record);
6897
6897
  const bytes = byteLength(readContent(record));
6898
6898
  const markers = [
6899
6899
  overwrite && "overwrites-existing",
6900
- path32?.outsideProject && "outside-project-directory",
6901
- path32?.nonAscii && "non-ascii-path"
6900
+ path34?.outsideProject && "outside-project-directory",
6901
+ path34?.nonAscii && "non-ascii-path"
6902
6902
  ];
6903
- if (path32 && /(^|\/)(\.env|\.npmrc|\.netrc|id_rsa|id_ed25519|credentials)(\.|$)/.test(path32.display)) {
6903
+ if (path34 && /(^|\/)(\.env|\.npmrc|\.netrc|id_rsa|id_ed25519|credentials)(\.|$)/.test(path34.display)) {
6904
6904
  markers.push("secret-adjacent");
6905
6905
  }
6906
6906
  const detail = bytes === null ? overwrite ? "replacing existing text" : null : `${bytes} byte${bytes === 1 ? "" : "s"}${overwrite ? ", replacing existing text" : ""}`;
6907
6907
  return {
6908
6908
  action: overwrite ? "Overwrite a file" : "Write a file",
6909
- subject: path32?.display ?? null,
6909
+ subject: path34?.display ?? null,
6910
6910
  detail,
6911
6911
  riskMarkers: normalizeMarkers(markers)
6912
6912
  };
@@ -7107,8 +7107,8 @@ function readPath2(source, dotted) {
7107
7107
  return current;
7108
7108
  }
7109
7109
  function firstString(source, paths) {
7110
- for (const path32 of paths ?? []) {
7111
- const value = readPath2(source, path32);
7110
+ for (const path34 of paths ?? []) {
7111
+ const value = readPath2(source, path34);
7112
7112
  if (typeof value === "string" && value.trim() !== "")
7113
7113
  return value.trim();
7114
7114
  }
@@ -7187,9 +7187,9 @@ function normalizeNativeEvent({ codec, payload, nativeEventName, nativeSessionId
7187
7187
  sealedInput.formatterVersion = FORMATTER_VERSION;
7188
7188
  if (rule.fileEditKind && (tool === "write" || tool === "edit")) {
7189
7189
  kind = rule.fileEditKind;
7190
- const path32 = reducePath(readPath2(input, "file_path") ?? readPath2(input, "filePath") ?? readPath2(input, "path") ?? readPath2(input, "notebook_path"), projectRoot);
7191
- if (path32)
7192
- sealedInput.paths = [path32.display];
7190
+ const path34 = reducePath(readPath2(input, "file_path") ?? readPath2(input, "filePath") ?? readPath2(input, "path") ?? readPath2(input, "notebook_path"), projectRoot);
7191
+ if (path34)
7192
+ sealedInput.paths = [path34.display];
7193
7193
  }
7194
7194
  idParts.push(tool, description.subject ?? "", description.detail ?? "");
7195
7195
  }
@@ -7619,8 +7619,8 @@ async function runAgentSessionInbox({
7619
7619
  const scope = resolveAgentSessionScope({ agent, env });
7620
7620
  if (!scope) return emptyResult("Empty");
7621
7621
  const payload = payloadRaw === void 0 ? parseNativePayload(readBoundedStdin()) : parseNativePayload(payloadRaw);
7622
- const path32 = resolveInjectPath({ agent, payload });
7623
- if (path32 === "unsupported") return emptyResult("Unsupported");
7622
+ const path34 = resolveInjectPath({ agent, payload });
7623
+ if (path34 === "unsupported") return emptyResult("Unsupported");
7624
7624
  const baseUrl = env.OVERLORD_BACKEND_URL?.trim();
7625
7625
  if (!baseUrl && !injectedClient) return emptyResult("Empty");
7626
7626
  const client = injectedClient ?? createChannelClient({ baseUrl, channelId: scope.channelId, token: scope.token });
@@ -7634,15 +7634,15 @@ async function runAgentSessionInbox({
7634
7634
  );
7635
7635
  if (!claimed.ok || !claimed.value.input) return emptyResult("Empty");
7636
7636
  const input = claimed.value.input;
7637
- return await emitClaimedInput({ agent, path: path32, input, client });
7637
+ return await emitClaimedInput({ agent, path: path34, input, client });
7638
7638
  }
7639
7639
  async function emitClaimedInput({
7640
7640
  agent,
7641
- path: path32,
7641
+ path: path34,
7642
7642
  input,
7643
7643
  client
7644
7644
  }) {
7645
- if (path32 === "claude-mid-turn") {
7645
+ if (path34 === "claude-mid-turn") {
7646
7646
  const emitted = await client.post(`/inputs/${input.id}/emitted`, {
7647
7647
  leaseId: input.leaseId,
7648
7648
  deliveryOutcome: "delivered"
@@ -7657,7 +7657,7 @@ async function emitClaimedInput({
7657
7657
  inputId: input.id
7658
7658
  };
7659
7659
  }
7660
- if (path32 === "claude-turn-boundary") {
7660
+ if (path34 === "claude-turn-boundary") {
7661
7661
  const emitted = await client.post(`/inputs/${input.id}/emitted`, {
7662
7662
  leaseId: input.leaseId,
7663
7663
  deliveryOutcome: "delivered"
@@ -7672,7 +7672,7 @@ async function emitClaimedInput({
7672
7672
  inputId: input.id
7673
7673
  };
7674
7674
  }
7675
- if (path32 === "cursor-turn-boundary") {
7675
+ if (path34 === "cursor-turn-boundary") {
7676
7676
  const emitted = await client.post(`/inputs/${input.id}/emitted`, {
7677
7677
  leaseId: input.leaseId,
7678
7678
  deliveryOutcome: "queued_turn_boundary"
@@ -7686,7 +7686,7 @@ async function emitClaimedInput({
7686
7686
  inputId: input.id
7687
7687
  };
7688
7688
  }
7689
- if (path32 === "codex-turn-boundary") {
7689
+ if (path34 === "codex-turn-boundary") {
7690
7690
  const emitted = await client.post(`/inputs/${input.id}/emitted`, {
7691
7691
  leaseId: input.leaseId,
7692
7692
  deliveryOutcome: "delivered"
@@ -7701,7 +7701,7 @@ async function emitClaimedInput({
7701
7701
  inputId: input.id
7702
7702
  };
7703
7703
  }
7704
- if (path32 === "pi-mid-turn") {
7704
+ if (path34 === "pi-mid-turn") {
7705
7705
  return {
7706
7706
  report: "Empty",
7707
7707
  exitCode: 0,
@@ -7806,8 +7806,8 @@ var init_inbox = __esm({
7806
7806
 
7807
7807
  // ../packages/core/dist/service/agent-session/pure/decision.js
7808
7808
  function firstValue(source, paths) {
7809
- for (const path32 of paths ?? []) {
7810
- const value = readPath2(source, path32);
7809
+ for (const path34 of paths ?? []) {
7810
+ const value = readPath2(source, path34);
7811
7811
  if (value !== void 0 && value !== null)
7812
7812
  return value;
7813
7813
  }
@@ -8397,10 +8397,10 @@ async function reconcileState({
8397
8397
  }) {
8398
8398
  let posted = 0;
8399
8399
  let duplicates = 0;
8400
- for (const path32 of ["/permission", "/question"]) {
8400
+ for (const path34 of ["/permission", "/question"]) {
8401
8401
  let entries;
8402
8402
  try {
8403
- const response = await doFetch(`${controlPlaneBaseUrl(port)}${path32}`, {
8403
+ const response = await doFetch(`${controlPlaneBaseUrl(port)}${path34}`, {
8404
8404
  headers: authHeaders(password)
8405
8405
  });
8406
8406
  if (!response.ok) continue;
@@ -8410,7 +8410,7 @@ async function reconcileState({
8410
8410
  continue;
8411
8411
  }
8412
8412
  for (const entry of entries) {
8413
- if (path32 === "/permission") {
8413
+ if (path34 === "/permission") {
8414
8414
  await syncOpenCodePermission({
8415
8415
  client,
8416
8416
  frame: { event: "permission.updated", data: JSON.stringify(entry) },
@@ -8933,17 +8933,17 @@ var require_visit = __commonJS({
8933
8933
  visit.BREAK = BREAK;
8934
8934
  visit.SKIP = SKIP;
8935
8935
  visit.REMOVE = REMOVE;
8936
- function visit_(key, node, visitor, path32) {
8937
- const ctrl = callVisitor(key, node, visitor, path32);
8936
+ function visit_(key, node, visitor, path34) {
8937
+ const ctrl = callVisitor(key, node, visitor, path34);
8938
8938
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
8939
- replaceNode(key, path32, ctrl);
8940
- return visit_(key, ctrl, visitor, path32);
8939
+ replaceNode(key, path34, ctrl);
8940
+ return visit_(key, ctrl, visitor, path34);
8941
8941
  }
8942
8942
  if (typeof ctrl !== "symbol") {
8943
8943
  if (identity.isCollection(node)) {
8944
- path32 = Object.freeze(path32.concat(node));
8944
+ path34 = Object.freeze(path34.concat(node));
8945
8945
  for (let i = 0; i < node.items.length; ++i) {
8946
- const ci = visit_(i, node.items[i], visitor, path32);
8946
+ const ci = visit_(i, node.items[i], visitor, path34);
8947
8947
  if (typeof ci === "number")
8948
8948
  i = ci - 1;
8949
8949
  else if (ci === BREAK)
@@ -8954,13 +8954,13 @@ var require_visit = __commonJS({
8954
8954
  }
8955
8955
  }
8956
8956
  } else if (identity.isPair(node)) {
8957
- path32 = Object.freeze(path32.concat(node));
8958
- const ck = visit_("key", node.key, visitor, path32);
8957
+ path34 = Object.freeze(path34.concat(node));
8958
+ const ck = visit_("key", node.key, visitor, path34);
8959
8959
  if (ck === BREAK)
8960
8960
  return BREAK;
8961
8961
  else if (ck === REMOVE)
8962
8962
  node.key = null;
8963
- const cv = visit_("value", node.value, visitor, path32);
8963
+ const cv = visit_("value", node.value, visitor, path34);
8964
8964
  if (cv === BREAK)
8965
8965
  return BREAK;
8966
8966
  else if (cv === REMOVE)
@@ -8981,17 +8981,17 @@ var require_visit = __commonJS({
8981
8981
  visitAsync.BREAK = BREAK;
8982
8982
  visitAsync.SKIP = SKIP;
8983
8983
  visitAsync.REMOVE = REMOVE;
8984
- async function visitAsync_(key, node, visitor, path32) {
8985
- const ctrl = await callVisitor(key, node, visitor, path32);
8984
+ async function visitAsync_(key, node, visitor, path34) {
8985
+ const ctrl = await callVisitor(key, node, visitor, path34);
8986
8986
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
8987
- replaceNode(key, path32, ctrl);
8988
- return visitAsync_(key, ctrl, visitor, path32);
8987
+ replaceNode(key, path34, ctrl);
8988
+ return visitAsync_(key, ctrl, visitor, path34);
8989
8989
  }
8990
8990
  if (typeof ctrl !== "symbol") {
8991
8991
  if (identity.isCollection(node)) {
8992
- path32 = Object.freeze(path32.concat(node));
8992
+ path34 = Object.freeze(path34.concat(node));
8993
8993
  for (let i = 0; i < node.items.length; ++i) {
8994
- const ci = await visitAsync_(i, node.items[i], visitor, path32);
8994
+ const ci = await visitAsync_(i, node.items[i], visitor, path34);
8995
8995
  if (typeof ci === "number")
8996
8996
  i = ci - 1;
8997
8997
  else if (ci === BREAK)
@@ -9002,13 +9002,13 @@ var require_visit = __commonJS({
9002
9002
  }
9003
9003
  }
9004
9004
  } else if (identity.isPair(node)) {
9005
- path32 = Object.freeze(path32.concat(node));
9006
- const ck = await visitAsync_("key", node.key, visitor, path32);
9005
+ path34 = Object.freeze(path34.concat(node));
9006
+ const ck = await visitAsync_("key", node.key, visitor, path34);
9007
9007
  if (ck === BREAK)
9008
9008
  return BREAK;
9009
9009
  else if (ck === REMOVE)
9010
9010
  node.key = null;
9011
- const cv = await visitAsync_("value", node.value, visitor, path32);
9011
+ const cv = await visitAsync_("value", node.value, visitor, path34);
9012
9012
  if (cv === BREAK)
9013
9013
  return BREAK;
9014
9014
  else if (cv === REMOVE)
@@ -9035,23 +9035,23 @@ var require_visit = __commonJS({
9035
9035
  }
9036
9036
  return visitor;
9037
9037
  }
9038
- function callVisitor(key, node, visitor, path32) {
9038
+ function callVisitor(key, node, visitor, path34) {
9039
9039
  if (typeof visitor === "function")
9040
- return visitor(key, node, path32);
9040
+ return visitor(key, node, path34);
9041
9041
  if (identity.isMap(node))
9042
- return visitor.Map?.(key, node, path32);
9042
+ return visitor.Map?.(key, node, path34);
9043
9043
  if (identity.isSeq(node))
9044
- return visitor.Seq?.(key, node, path32);
9044
+ return visitor.Seq?.(key, node, path34);
9045
9045
  if (identity.isPair(node))
9046
- return visitor.Pair?.(key, node, path32);
9046
+ return visitor.Pair?.(key, node, path34);
9047
9047
  if (identity.isScalar(node))
9048
- return visitor.Scalar?.(key, node, path32);
9048
+ return visitor.Scalar?.(key, node, path34);
9049
9049
  if (identity.isAlias(node))
9050
- return visitor.Alias?.(key, node, path32);
9050
+ return visitor.Alias?.(key, node, path34);
9051
9051
  return void 0;
9052
9052
  }
9053
- function replaceNode(key, path32, node) {
9054
- const parent = path32[path32.length - 1];
9053
+ function replaceNode(key, path34, node) {
9054
+ const parent = path34[path34.length - 1];
9055
9055
  if (identity.isCollection(parent)) {
9056
9056
  parent.items[key] = node;
9057
9057
  } else if (identity.isPair(parent)) {
@@ -9661,10 +9661,10 @@ var require_Collection = __commonJS({
9661
9661
  var createNode = require_createNode();
9662
9662
  var identity = require_identity();
9663
9663
  var Node = require_Node();
9664
- function collectionFromPath(schema, path32, value) {
9664
+ function collectionFromPath(schema, path34, value) {
9665
9665
  let v = value;
9666
- for (let i = path32.length - 1; i >= 0; --i) {
9667
- const k = path32[i];
9666
+ for (let i = path34.length - 1; i >= 0; --i) {
9667
+ const k = path34[i];
9668
9668
  if (typeof k === "number" && Number.isInteger(k) && k >= 0) {
9669
9669
  const a = [];
9670
9670
  a[k] = v;
@@ -9683,7 +9683,7 @@ var require_Collection = __commonJS({
9683
9683
  sourceObjects: /* @__PURE__ */ new Map()
9684
9684
  });
9685
9685
  }
9686
- var isEmptyPath = (path32) => path32 == null || typeof path32 === "object" && !!path32[Symbol.iterator]().next().done;
9686
+ var isEmptyPath = (path34) => path34 == null || typeof path34 === "object" && !!path34[Symbol.iterator]().next().done;
9687
9687
  var Collection = class extends Node.NodeBase {
9688
9688
  constructor(type, schema) {
9689
9689
  super(type);
@@ -9713,11 +9713,11 @@ var require_Collection = __commonJS({
9713
9713
  * be a Pair instance or a `{ key, value }` object, which may not have a key
9714
9714
  * that already exists in the map.
9715
9715
  */
9716
- addIn(path32, value) {
9717
- if (isEmptyPath(path32))
9716
+ addIn(path34, value) {
9717
+ if (isEmptyPath(path34))
9718
9718
  this.add(value);
9719
9719
  else {
9720
- const [key, ...rest] = path32;
9720
+ const [key, ...rest] = path34;
9721
9721
  const node = this.get(key, true);
9722
9722
  if (identity.isCollection(node))
9723
9723
  node.addIn(rest, value);
@@ -9731,8 +9731,8 @@ var require_Collection = __commonJS({
9731
9731
  * Removes a value from the collection.
9732
9732
  * @returns `true` if the item was found and removed.
9733
9733
  */
9734
- deleteIn(path32) {
9735
- const [key, ...rest] = path32;
9734
+ deleteIn(path34) {
9735
+ const [key, ...rest] = path34;
9736
9736
  if (rest.length === 0)
9737
9737
  return this.delete(key);
9738
9738
  const node = this.get(key, true);
@@ -9746,8 +9746,8 @@ var require_Collection = __commonJS({
9746
9746
  * scalar values from their surrounding node; to disable set `keepScalar` to
9747
9747
  * `true` (collections are always returned intact).
9748
9748
  */
9749
- getIn(path32, keepScalar) {
9750
- const [key, ...rest] = path32;
9749
+ getIn(path34, keepScalar) {
9750
+ const [key, ...rest] = path34;
9751
9751
  const node = this.get(key, true);
9752
9752
  if (rest.length === 0)
9753
9753
  return !keepScalar && identity.isScalar(node) ? node.value : node;
@@ -9765,8 +9765,8 @@ var require_Collection = __commonJS({
9765
9765
  /**
9766
9766
  * Checks if the collection includes a value with the key `key`.
9767
9767
  */
9768
- hasIn(path32) {
9769
- const [key, ...rest] = path32;
9768
+ hasIn(path34) {
9769
+ const [key, ...rest] = path34;
9770
9770
  if (rest.length === 0)
9771
9771
  return this.has(key);
9772
9772
  const node = this.get(key, true);
@@ -9776,8 +9776,8 @@ var require_Collection = __commonJS({
9776
9776
  * Sets a value in this collection. For `!!set`, `value` needs to be a
9777
9777
  * boolean to add/remove the item from the set.
9778
9778
  */
9779
- setIn(path32, value) {
9780
- const [key, ...rest] = path32;
9779
+ setIn(path34, value) {
9780
+ const [key, ...rest] = path34;
9781
9781
  if (rest.length === 0) {
9782
9782
  this.set(key, value);
9783
9783
  } else {
@@ -12292,9 +12292,9 @@ var require_Document = __commonJS({
12292
12292
  this.contents.add(value);
12293
12293
  }
12294
12294
  /** Adds a value to the document. */
12295
- addIn(path32, value) {
12295
+ addIn(path34, value) {
12296
12296
  if (assertCollection(this.contents))
12297
- this.contents.addIn(path32, value);
12297
+ this.contents.addIn(path34, value);
12298
12298
  }
12299
12299
  /**
12300
12300
  * Create a new `Alias` node, ensuring that the target `node` has the required anchor.
@@ -12369,14 +12369,14 @@ var require_Document = __commonJS({
12369
12369
  * Removes a value from the document.
12370
12370
  * @returns `true` if the item was found and removed.
12371
12371
  */
12372
- deleteIn(path32) {
12373
- if (Collection.isEmptyPath(path32)) {
12372
+ deleteIn(path34) {
12373
+ if (Collection.isEmptyPath(path34)) {
12374
12374
  if (this.contents == null)
12375
12375
  return false;
12376
12376
  this.contents = null;
12377
12377
  return true;
12378
12378
  }
12379
- return assertCollection(this.contents) ? this.contents.deleteIn(path32) : false;
12379
+ return assertCollection(this.contents) ? this.contents.deleteIn(path34) : false;
12380
12380
  }
12381
12381
  /**
12382
12382
  * Returns item at `key`, or `undefined` if not found. By default unwraps
@@ -12391,10 +12391,10 @@ var require_Document = __commonJS({
12391
12391
  * scalar values from their surrounding node; to disable set `keepScalar` to
12392
12392
  * `true` (collections are always returned intact).
12393
12393
  */
12394
- getIn(path32, keepScalar) {
12395
- if (Collection.isEmptyPath(path32))
12394
+ getIn(path34, keepScalar) {
12395
+ if (Collection.isEmptyPath(path34))
12396
12396
  return !keepScalar && identity.isScalar(this.contents) ? this.contents.value : this.contents;
12397
- return identity.isCollection(this.contents) ? this.contents.getIn(path32, keepScalar) : void 0;
12397
+ return identity.isCollection(this.contents) ? this.contents.getIn(path34, keepScalar) : void 0;
12398
12398
  }
12399
12399
  /**
12400
12400
  * Checks if the document includes a value with the key `key`.
@@ -12405,10 +12405,10 @@ var require_Document = __commonJS({
12405
12405
  /**
12406
12406
  * Checks if the document includes a value at `path`.
12407
12407
  */
12408
- hasIn(path32) {
12409
- if (Collection.isEmptyPath(path32))
12408
+ hasIn(path34) {
12409
+ if (Collection.isEmptyPath(path34))
12410
12410
  return this.contents !== void 0;
12411
- return identity.isCollection(this.contents) ? this.contents.hasIn(path32) : false;
12411
+ return identity.isCollection(this.contents) ? this.contents.hasIn(path34) : false;
12412
12412
  }
12413
12413
  /**
12414
12414
  * Sets a value in this document. For `!!set`, `value` needs to be a
@@ -12425,13 +12425,13 @@ var require_Document = __commonJS({
12425
12425
  * Sets a value in this document. For `!!set`, `value` needs to be a
12426
12426
  * boolean to add/remove the item from the set.
12427
12427
  */
12428
- setIn(path32, value) {
12429
- if (Collection.isEmptyPath(path32)) {
12428
+ setIn(path34, value) {
12429
+ if (Collection.isEmptyPath(path34)) {
12430
12430
  this.contents = value;
12431
12431
  } else if (this.contents == null) {
12432
- this.contents = Collection.collectionFromPath(this.schema, Array.from(path32), value);
12432
+ this.contents = Collection.collectionFromPath(this.schema, Array.from(path34), value);
12433
12433
  } else if (assertCollection(this.contents)) {
12434
- this.contents.setIn(path32, value);
12434
+ this.contents.setIn(path34, value);
12435
12435
  }
12436
12436
  }
12437
12437
  /**
@@ -14391,9 +14391,9 @@ var require_cst_visit = __commonJS({
14391
14391
  visit.BREAK = BREAK;
14392
14392
  visit.SKIP = SKIP;
14393
14393
  visit.REMOVE = REMOVE;
14394
- visit.itemAtPath = (cst, path32) => {
14394
+ visit.itemAtPath = (cst, path34) => {
14395
14395
  let item = cst;
14396
- for (const [field, index] of path32) {
14396
+ for (const [field, index] of path34) {
14397
14397
  const tok = item?.[field];
14398
14398
  if (tok && "items" in tok) {
14399
14399
  item = tok.items[index];
@@ -14402,23 +14402,23 @@ var require_cst_visit = __commonJS({
14402
14402
  }
14403
14403
  return item;
14404
14404
  };
14405
- visit.parentCollection = (cst, path32) => {
14406
- const parent = visit.itemAtPath(cst, path32.slice(0, -1));
14407
- const field = path32[path32.length - 1][0];
14405
+ visit.parentCollection = (cst, path34) => {
14406
+ const parent = visit.itemAtPath(cst, path34.slice(0, -1));
14407
+ const field = path34[path34.length - 1][0];
14408
14408
  const coll = parent?.[field];
14409
14409
  if (coll && "items" in coll)
14410
14410
  return coll;
14411
14411
  throw new Error("Parent collection not found");
14412
14412
  };
14413
- function _visit(path32, item, visitor) {
14414
- let ctrl = visitor(item, path32);
14413
+ function _visit(path34, item, visitor) {
14414
+ let ctrl = visitor(item, path34);
14415
14415
  if (typeof ctrl === "symbol")
14416
14416
  return ctrl;
14417
14417
  for (const field of ["key", "value"]) {
14418
14418
  const token = item[field];
14419
14419
  if (token && "items" in token) {
14420
14420
  for (let i = 0; i < token.items.length; ++i) {
14421
- const ci = _visit(Object.freeze(path32.concat([[field, i]])), token.items[i], visitor);
14421
+ const ci = _visit(Object.freeze(path34.concat([[field, i]])), token.items[i], visitor);
14422
14422
  if (typeof ci === "number")
14423
14423
  i = ci - 1;
14424
14424
  else if (ci === BREAK)
@@ -14429,10 +14429,10 @@ var require_cst_visit = __commonJS({
14429
14429
  }
14430
14430
  }
14431
14431
  if (typeof ctrl === "function" && field === "key")
14432
- ctrl = ctrl(item, path32);
14432
+ ctrl = ctrl(item, path34);
14433
14433
  }
14434
14434
  }
14435
- return typeof ctrl === "function" ? ctrl(item, path32) : ctrl;
14435
+ return typeof ctrl === "function" ? ctrl(item, path34) : ctrl;
14436
14436
  }
14437
14437
  exports.visit = visit;
14438
14438
  }
@@ -16343,22 +16343,22 @@ var init_contract = __esm({
16343
16343
 
16344
16344
  // ../packages/contract/dist/agent-launch-flags.js
16345
16345
  function parseAgentLaunchFlagText(text) {
16346
- const trimmed = text.trim();
16347
- if (!trimmed)
16346
+ const trimmed5 = text.trim();
16347
+ if (!trimmed5)
16348
16348
  return null;
16349
- const eqIndex = trimmed.indexOf("=");
16350
- if (eqIndex > 0 && trimmed.startsWith("--")) {
16351
- const name = trimmed.slice(0, eqIndex).trim();
16352
- const value = trimmed.slice(eqIndex + 1).trim();
16349
+ const eqIndex = trimmed5.indexOf("=");
16350
+ if (eqIndex > 0 && trimmed5.startsWith("--")) {
16351
+ const name = trimmed5.slice(0, eqIndex).trim();
16352
+ const value = trimmed5.slice(eqIndex + 1).trim();
16353
16353
  return name ? { name, value: value.length > 0 ? value : null } : null;
16354
16354
  }
16355
- const spaceIndex = trimmed.indexOf(" ");
16356
- if (spaceIndex > 0 && trimmed.startsWith("--")) {
16357
- const name = trimmed.slice(0, spaceIndex).trim();
16358
- const value = trimmed.slice(spaceIndex + 1).trim();
16355
+ const spaceIndex = trimmed5.indexOf(" ");
16356
+ if (spaceIndex > 0 && trimmed5.startsWith("--")) {
16357
+ const name = trimmed5.slice(0, spaceIndex).trim();
16358
+ const value = trimmed5.slice(spaceIndex + 1).trim();
16359
16359
  return name ? { name, value: value.length > 0 ? value : null } : null;
16360
16360
  }
16361
- return { name: trimmed };
16361
+ return { name: trimmed5 };
16362
16362
  }
16363
16363
  function normalizeAgentLaunchFlags(input) {
16364
16364
  if (!Array.isArray(input))
@@ -16508,12 +16508,12 @@ function accessModeToResourcePathPermission({ accessMode, isPrimary = false }) {
16508
16508
  return "rw";
16509
16509
  return accessMode === "read" ? "ro" : "rw";
16510
16510
  }
16511
- function formatResourcePathWithPermission({ path: path32, accessMode, isPrimary = false }) {
16512
- const trimmed = path32.trim();
16513
- if (!trimmed)
16511
+ function formatResourcePathWithPermission({ path: path34, accessMode, isPrimary = false }) {
16512
+ const trimmed5 = path34.trim();
16513
+ if (!trimmed5)
16514
16514
  return "";
16515
16515
  const permission = accessModeToResourcePathPermission({ accessMode, isPrimary });
16516
- return `${trimmed}:${permission}`;
16516
+ return `${trimmed5}:${permission}`;
16517
16517
  }
16518
16518
  function formatProjectResourcePathsFromManifest(projectResources) {
16519
16519
  if (!Array.isArray(projectResources))
@@ -16523,11 +16523,11 @@ function formatProjectResourcePathsFromManifest(projectResources) {
16523
16523
  if (!entry || typeof entry !== "object")
16524
16524
  continue;
16525
16525
  const record = entry;
16526
- const path32 = typeof record.path === "string" ? record.path.trim() : "";
16527
- if (!path32)
16526
+ const path34 = typeof record.path === "string" ? record.path.trim() : "";
16527
+ if (!path34)
16528
16528
  continue;
16529
16529
  paths.push(formatResourcePathWithPermission({
16530
- path: path32,
16530
+ path: path34,
16531
16531
  accessMode: typeof record.accessMode === "string" ? record.accessMode : null,
16532
16532
  isPrimary: record.isPrimary === true
16533
16533
  }));
@@ -16784,11 +16784,545 @@ var init_git_tree = __esm({
16784
16784
  }
16785
16785
  });
16786
16786
 
16787
- // ../packages/core/dist/service/local-target/git-run.js
16787
+ // ../packages/core/dist/service/terminal-profile-types.js
16788
+ function trimmed(value) {
16789
+ return typeof value === "string" && value.trim() ? value.trim() : null;
16790
+ }
16791
+ function viewerKindForLauncher(launcher) {
16792
+ const value = trimmed(launcher);
16793
+ if (!value)
16794
+ return "inline";
16795
+ const lowered = value.toLowerCase();
16796
+ if (lowered === "iterm2" || lowered === "iterm")
16797
+ return "iterm";
16798
+ if (lowered === "terminal")
16799
+ return "terminal";
16800
+ return "custom";
16801
+ }
16802
+ function normalizeExecutionProvider(value) {
16803
+ if (!value || typeof value !== "object" || Array.isArray(value))
16804
+ return null;
16805
+ const cast = value;
16806
+ const kind = trimmed(cast.kind)?.toLowerCase() === "latch" ? "latch" : "direct";
16807
+ return {
16808
+ kind,
16809
+ executable: trimmed(cast.executable) ?? DEFAULT_LATCH_EXECUTABLE
16810
+ };
16811
+ }
16812
+ function launchSessionSnapshotFromMetadata(metadata) {
16813
+ const raw = metadata?.[LAUNCH_SESSION_METADATA_KEY];
16814
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
16815
+ return null;
16816
+ const cast = raw;
16817
+ if (cast.version !== TERMINAL_PROFILE_VERSION)
16818
+ return null;
16819
+ const viewer = cast.viewer && typeof cast.viewer === "object" && !Array.isArray(cast.viewer) ? cast.viewer : null;
16820
+ const launcher = trimmed(viewer?.launcher);
16821
+ const source = (value) => trimmed(value) === "target" ? "target" : "user_default";
16822
+ return {
16823
+ version: TERMINAL_PROFILE_VERSION,
16824
+ executionProvider: normalizeExecutionProvider(cast.executionProvider) ?? {
16825
+ ...DEFAULT_EXECUTION_PROVIDER
16826
+ },
16827
+ viewer: {
16828
+ kind: trimmed(viewer?.kind) ? trimmed(viewer?.kind) : viewerKindForLauncher(launcher),
16829
+ launcher,
16830
+ openOnLaunch: viewer?.openOnLaunch !== false
16831
+ },
16832
+ executionProviderSource: source(cast.executionProviderSource),
16833
+ viewerOpenSource: source(cast.viewerOpenSource),
16834
+ resolvedAt: trimmed(cast.resolvedAt) ?? ""
16835
+ };
16836
+ }
16837
+ var TERMINAL_PROFILE_VERSION, DEFAULT_LATCH_EXECUTABLE, DEFAULT_EXECUTION_PROVIDER, DEFAULT_OPEN_VIEWER_ON_LAUNCH, DEFAULT_LAUNCH_SESSION_DEFAULTS, LAUNCH_SESSION_METADATA_KEY;
16838
+ var init_terminal_profile_types2 = __esm({
16839
+ "../packages/core/dist/service/terminal-profile-types.js"() {
16840
+ "use strict";
16841
+ TERMINAL_PROFILE_VERSION = 1;
16842
+ DEFAULT_LATCH_EXECUTABLE = "latch";
16843
+ DEFAULT_EXECUTION_PROVIDER = {
16844
+ kind: "direct",
16845
+ executable: DEFAULT_LATCH_EXECUTABLE
16846
+ };
16847
+ DEFAULT_OPEN_VIEWER_ON_LAUNCH = true;
16848
+ DEFAULT_LAUNCH_SESSION_DEFAULTS = {
16849
+ executionProvider: { ...DEFAULT_EXECUTION_PROVIDER },
16850
+ openViewerOnLaunch: DEFAULT_OPEN_VIEWER_ON_LAUNCH
16851
+ };
16852
+ LAUNCH_SESSION_METADATA_KEY = "launchSession";
16853
+ }
16854
+ });
16855
+
16856
+ // ../packages/core/dist/service/latch-discovery.js
16788
16857
  import { execFileSync as execFileSync3 } from "node:child_process";
16858
+ import { existsSync as existsSync16, mkdirSync as mkdirSync9, readFileSync as readFileSync15, statSync as statSync4, writeFileSync as writeFileSync8 } from "node:fs";
16859
+ import os3 from "node:os";
16860
+ import path17 from "node:path";
16861
+ function defaultLatchDiscoveryCachePath() {
16862
+ const home = process.env.OVLD_HOME?.trim() || path17.join(os3.homedir(), ".ovld");
16863
+ return path17.join(home, LATCH_DISCOVERY_CACHE_FILENAME);
16864
+ }
16865
+ function trimmed2(value) {
16866
+ return typeof value === "string" && value.trim() ? value.trim() : null;
16867
+ }
16868
+ function asBoolean(value) {
16869
+ return value === true;
16870
+ }
16871
+ function asStringArray(value) {
16872
+ if (!Array.isArray(value))
16873
+ return [];
16874
+ return value.filter((entry) => typeof entry === "string");
16875
+ }
16876
+ function parseLatchCapabilitiesReport(raw) {
16877
+ const text = raw.trim();
16878
+ if (!text)
16879
+ return null;
16880
+ let parsed;
16881
+ try {
16882
+ parsed = JSON.parse(text);
16883
+ } catch {
16884
+ return null;
16885
+ }
16886
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
16887
+ return null;
16888
+ const cast = parsed;
16889
+ const protocolVersion = typeof cast.protocolVersion === "number" && Number.isFinite(cast.protocolVersion) ? Math.trunc(cast.protocolVersion) : null;
16890
+ const productVersion = trimmed2(cast.productVersion);
16891
+ if (protocolVersion === null || !productVersion)
16892
+ return null;
16893
+ if (!cast.capabilities || typeof cast.capabilities !== "object" || Array.isArray(cast.capabilities)) {
16894
+ return null;
16895
+ }
16896
+ const caps = cast.capabilities;
16897
+ return {
16898
+ protocolVersion,
16899
+ productVersion,
16900
+ capabilities: {
16901
+ create: asBoolean(caps.create),
16902
+ openViewer: asBoolean(caps.openViewer),
16903
+ localAttach: asBoolean(caps.localAttach),
16904
+ cloudAttach: asBoolean(caps.cloudAttach),
16905
+ selfUpdate: asBoolean(caps.selfUpdate),
16906
+ extensions: asStringArray(caps.extensions)
16907
+ }
16908
+ };
16909
+ }
16910
+ function evaluateLatchCapabilities({ report, executable, resolvedPath, checkedAt = (/* @__PURE__ */ new Date()).toISOString() }) {
16911
+ if (report.protocolVersion !== SUPPORTED_LATCH_PROTOCOL_VERSION) {
16912
+ return {
16913
+ state: "incompatible",
16914
+ executable,
16915
+ resolvedPath,
16916
+ protocolVersion: report.protocolVersion,
16917
+ productVersion: report.productVersion,
16918
+ missingCapability: "protocolVersion",
16919
+ detail: `Latch protocolVersion ${report.protocolVersion} is not supported (need ${SUPPORTED_LATCH_PROTOCOL_VERSION}).`,
16920
+ checkedAt,
16921
+ latchSelectable: false,
16922
+ directSelectable: true
16923
+ };
16924
+ }
16925
+ for (const required of REQUIRED_LATCH_CAPABILITIES) {
16926
+ if (!report.capabilities[required]) {
16927
+ return {
16928
+ state: "incompatible",
16929
+ executable,
16930
+ resolvedPath,
16931
+ protocolVersion: report.protocolVersion,
16932
+ productVersion: report.productVersion,
16933
+ missingCapability: required,
16934
+ detail: `Latch is missing required capability \`${required}\`.`,
16935
+ checkedAt,
16936
+ latchSelectable: false,
16937
+ directSelectable: true
16938
+ };
16939
+ }
16940
+ }
16941
+ return {
16942
+ state: "found",
16943
+ executable,
16944
+ resolvedPath,
16945
+ protocolVersion: report.protocolVersion,
16946
+ productVersion: report.productVersion,
16947
+ capabilities: report.capabilities,
16948
+ checkedAt,
16949
+ latchSelectable: true,
16950
+ directSelectable: true
16951
+ };
16952
+ }
16953
+ function resolveLatchExecutablePath(executable) {
16954
+ const name = trimmed2(executable) ?? DEFAULT_LATCH_EXECUTABLE;
16955
+ if (path17.isAbsolute(name) || name.includes("/") || name.includes("\\")) {
16956
+ return existsSync16(name) ? path17.resolve(name) : null;
16957
+ }
16958
+ try {
16959
+ const found = execFileSync3("which", [name], {
16960
+ encoding: "utf8",
16961
+ stdio: ["ignore", "pipe", "ignore"]
16962
+ }).trim();
16963
+ return found || null;
16964
+ } catch {
16965
+ return null;
16966
+ }
16967
+ }
16968
+ function notInstalledResult({ executable, checkedAt }) {
16969
+ return {
16970
+ state: "not_installed",
16971
+ executable,
16972
+ installCommand: LATCH_STANDALONE_INSTALL_COMMAND,
16973
+ checkedAt,
16974
+ latchSelectable: false,
16975
+ directSelectable: true
16976
+ };
16977
+ }
16978
+ function probeLatchCapabilities({ executable = DEFAULT_LATCH_EXECUTABLE, resolvePath = resolveLatchExecutablePath, runCommand: runCommand2 = defaultCommandRunner, now = () => (/* @__PURE__ */ new Date()).toISOString() } = {}) {
16979
+ const exe = trimmed2(executable) ?? DEFAULT_LATCH_EXECUTABLE;
16980
+ const checkedAt = now();
16981
+ const resolvedPath = resolvePath(exe);
16982
+ if (!resolvedPath) {
16983
+ return notInstalledResult({ executable: exe, checkedAt });
16984
+ }
16985
+ const ran = runCommand2({ executable: resolvedPath, argv: ["capabilities", "--json"] });
16986
+ if (ran.status === null && ran.stderr === "ENOENT") {
16987
+ return notInstalledResult({ executable: exe, checkedAt });
16988
+ }
16989
+ const report = parseLatchCapabilitiesReport(ran.stdout);
16990
+ if (!report) {
16991
+ return {
16992
+ state: "incompatible",
16993
+ executable: exe,
16994
+ resolvedPath,
16995
+ protocolVersion: null,
16996
+ productVersion: null,
16997
+ missingCapability: "capabilities",
16998
+ detail: ran.status === 0 ? "Latch capabilities output was not valid JSON in the expected shape." : `Latch capabilities failed (exit ${ran.status ?? "null"}).`,
16999
+ checkedAt,
17000
+ latchSelectable: false,
17001
+ directSelectable: true
17002
+ };
17003
+ }
17004
+ return evaluateLatchCapabilities({ report, executable: exe, resolvedPath, checkedAt });
17005
+ }
17006
+ function latchDiscoveryCacheKey({ executionTargetId, executable }) {
17007
+ const exe = trimmed2(executable) ?? DEFAULT_LATCH_EXECUTABLE;
17008
+ return `${executionTargetId}::${exe}`;
17009
+ }
17010
+ function readBinaryMtimeMs(resolvedPath) {
17011
+ if (!resolvedPath)
17012
+ return null;
17013
+ try {
17014
+ return statSync4(resolvedPath).mtimeMs;
17015
+ } catch {
17016
+ return null;
17017
+ }
17018
+ }
17019
+ function isLatchDiscoveryCacheFresh({ entry, resolvePath = resolveLatchExecutablePath }) {
17020
+ const { result } = entry;
17021
+ if (result.state === "not_installed") {
17022
+ return resolvePath(result.executable) === null;
17023
+ }
17024
+ const pathStill = result.resolvedPath;
17025
+ if (!pathStill || !existsSync16(pathStill))
17026
+ return false;
17027
+ const mtime = readBinaryMtimeMs(pathStill);
17028
+ if (mtime === null || entry.binaryMtimeMs === null)
17029
+ return false;
17030
+ return mtime === entry.binaryMtimeMs;
17031
+ }
17032
+ function readLatchDiscoveryCacheFile(filePath) {
17033
+ if (!existsSync16(filePath))
17034
+ return { version: 1, entries: {} };
17035
+ try {
17036
+ const parsed = JSON.parse(readFileSync15(filePath, "utf8"));
17037
+ if (parsed.version !== 1 || !parsed.entries || typeof parsed.entries !== "object") {
17038
+ return { version: 1, entries: {} };
17039
+ }
17040
+ return { version: 1, entries: parsed.entries };
17041
+ } catch {
17042
+ return { version: 1, entries: {} };
17043
+ }
17044
+ }
17045
+ function writeLatchDiscoveryCacheFile({ filePath, cache }) {
17046
+ mkdirSync9(path17.dirname(filePath), { recursive: true });
17047
+ writeFileSync8(filePath, `${JSON.stringify(cache, null, 2)}
17048
+ `, { mode: 384 });
17049
+ }
17050
+ function discoverLatchForExecutionTarget({ executionTargetId, executable = DEFAULT_LATCH_EXECUTABLE, cacheFilePath, force = false, resolvePath = resolveLatchExecutablePath, runCommand: runCommand2 = defaultCommandRunner, now = () => (/* @__PURE__ */ new Date()).toISOString() }) {
17051
+ const exe = trimmed2(executable) ?? DEFAULT_LATCH_EXECUTABLE;
17052
+ const key = latchDiscoveryCacheKey({ executionTargetId, executable: exe });
17053
+ const cache = readLatchDiscoveryCacheFile(cacheFilePath);
17054
+ const existing = cache.entries[key];
17055
+ if (!force && existing && isLatchDiscoveryCacheFresh({ entry: existing, resolvePath })) {
17056
+ return { ...existing.result, checkedAt: existing.result.checkedAt, directSelectable: true };
17057
+ }
17058
+ const result = probeLatchCapabilities({ executable: exe, resolvePath, runCommand: runCommand2, now });
17059
+ const binaryMtimeMs = result.state === "not_installed" ? null : readBinaryMtimeMs(result.resolvedPath);
17060
+ cache.entries[key] = {
17061
+ result,
17062
+ binaryMtimeMs,
17063
+ cachedAt: result.checkedAt
17064
+ };
17065
+ writeLatchDiscoveryCacheFile({ filePath: cacheFilePath, cache });
17066
+ return result;
17067
+ }
17068
+ var SUPPORTED_LATCH_PROTOCOL_VERSION, REQUIRED_LATCH_CAPABILITIES, LATCH_STANDALONE_INSTALL_COMMAND, LATCH_DISCOVERY_CACHE_FILENAME, defaultCommandRunner;
17069
+ var init_latch_discovery = __esm({
17070
+ "../packages/core/dist/service/latch-discovery.js"() {
17071
+ "use strict";
17072
+ init_terminal_profile_types2();
17073
+ SUPPORTED_LATCH_PROTOCOL_VERSION = 1;
17074
+ REQUIRED_LATCH_CAPABILITIES = ["create"];
17075
+ LATCH_STANDALONE_INSTALL_COMMAND = "curl -fsSL https://raw.githubusercontent.com/jchaselubitz/Latch/main/scripts/install-cli.sh | bash";
17076
+ LATCH_DISCOVERY_CACHE_FILENAME = "latch-discovery.json";
17077
+ defaultCommandRunner = ({ executable, argv }) => {
17078
+ try {
17079
+ const stdout = execFileSync3(executable, argv, {
17080
+ encoding: "utf8",
17081
+ stdio: ["ignore", "pipe", "pipe"],
17082
+ timeout: 5e3
17083
+ });
17084
+ return { status: 0, stdout: String(stdout), stderr: "" };
17085
+ } catch (error) {
17086
+ const err = error;
17087
+ if (err.code === "ENOENT") {
17088
+ return { status: null, stdout: "", stderr: "ENOENT" };
17089
+ }
17090
+ return {
17091
+ status: typeof err.status === "number" ? err.status : 1,
17092
+ stdout: err.stdout ? String(err.stdout) : "",
17093
+ stderr: err.stderr ? String(err.stderr) : String(error)
17094
+ };
17095
+ }
17096
+ };
17097
+ }
17098
+ });
17099
+
17100
+ // ../packages/core/dist/service/latch-launch.js
17101
+ function trimmed3(value) {
17102
+ return typeof value === "string" && value.trim() ? value.trim() : null;
17103
+ }
17104
+ function buildLatchCreateManifest({ commandString, shell = process.env.SHELL?.trim() || "/bin/bash", cwd, env, size = DEFAULT_LATCH_TERMINAL_SIZE, title, name, commandLabel, externalRunId }) {
17105
+ const shellPath = trimmed3(shell) ?? "/bin/bash";
17106
+ const cleanedEnv = {};
17107
+ for (const [key, value] of Object.entries(env)) {
17108
+ if (key.trim() && typeof value === "string")
17109
+ cleanedEnv[key] = value;
17110
+ }
17111
+ const display = {
17112
+ source: {
17113
+ kind: "overlord",
17114
+ ...trimmed3(externalRunId) ? { external_run_id: trimmed3(externalRunId) } : {}
17115
+ }
17116
+ };
17117
+ if (trimmed3(title))
17118
+ display.title = trimmed3(title);
17119
+ if (trimmed3(name))
17120
+ display.name = trimmed3(name);
17121
+ if (trimmed3(commandLabel))
17122
+ display.command_label = trimmed3(commandLabel);
17123
+ return {
17124
+ format_version: LATCH_MANIFEST_FORMAT_VERSION,
17125
+ launch: {
17126
+ argv: [shellPath, "-lc", commandString],
17127
+ cwd,
17128
+ env: cleanedEnv,
17129
+ inherit_env: true,
17130
+ size: {
17131
+ cols: Math.max(1, Math.floor(size.cols) || DEFAULT_LATCH_TERMINAL_SIZE.cols),
17132
+ rows: Math.max(1, Math.floor(size.rows) || DEFAULT_LATCH_TERMINAL_SIZE.rows)
17133
+ }
17134
+ },
17135
+ display
17136
+ };
17137
+ }
17138
+ function parseLatchCreateReport(raw) {
17139
+ try {
17140
+ const parsed = JSON.parse(raw);
17141
+ const id = trimmed3(parsed.session?.id);
17142
+ if (!id)
17143
+ return null;
17144
+ const protocolVersion = typeof parsed.protocolVersion === "number" && Number.isFinite(parsed.protocolVersion) ? parsed.protocolVersion : LATCH_MANIFEST_FORMAT_VERSION;
17145
+ return {
17146
+ protocolVersion,
17147
+ session: {
17148
+ id,
17149
+ name: trimmed3(parsed.session?.name) ?? id,
17150
+ state: trimmed3(parsed.session?.state) ?? "running",
17151
+ createdAt: trimmed3(parsed.session?.createdAt) ?? (/* @__PURE__ */ new Date()).toISOString()
17152
+ }
17153
+ };
17154
+ } catch {
17155
+ return null;
17156
+ }
17157
+ }
17158
+ function toExecutionProviderSession({ createReport, executionTargetId, createdAt }) {
17159
+ return {
17160
+ provider: "latch",
17161
+ providerSessionId: createReport.session.id,
17162
+ sessionName: createReport.session.name,
17163
+ executionTargetId: trimmed3(executionTargetId),
17164
+ agentSessionId: null,
17165
+ createdAt: createdAt ?? createReport.session.createdAt,
17166
+ lastObservedState: createReport.session.state
17167
+ };
17168
+ }
17169
+ function existingLatchProviderSession({ latchSessionId, executionTargetId, createdAt = (/* @__PURE__ */ new Date()).toISOString() }) {
17170
+ const providerSessionId = trimmed3(latchSessionId);
17171
+ if (!providerSessionId)
17172
+ return null;
17173
+ return {
17174
+ provider: "latch",
17175
+ providerSessionId,
17176
+ sessionName: null,
17177
+ executionTargetId: trimmed3(executionTargetId),
17178
+ agentSessionId: null,
17179
+ createdAt,
17180
+ lastObservedState: "running"
17181
+ };
17182
+ }
17183
+ function latchViewerFlagForKind(kind) {
17184
+ switch (trimmed3(kind)?.toLowerCase()) {
17185
+ case "iterm":
17186
+ case "iterm2":
17187
+ return "iterm";
17188
+ default:
17189
+ return null;
17190
+ }
17191
+ }
17192
+ function latchAttachCommand({ executable = "latch", providerSessionId }) {
17193
+ return `${trimmed3(executable) ?? "latch"} attach ${providerSessionId}`;
17194
+ }
17195
+ function shouldUseLatchProvider({ providerKind, latchSelectable }) {
17196
+ return trimmed3(providerKind)?.toLowerCase() === "latch" && latchSelectable === true;
17197
+ }
17198
+ var LATCH_MANIFEST_FORMAT_VERSION, DEFAULT_LATCH_TERMINAL_SIZE;
17199
+ var init_latch_launch = __esm({
17200
+ "../packages/core/dist/service/latch-launch.js"() {
17201
+ "use strict";
17202
+ LATCH_MANIFEST_FORMAT_VERSION = 1;
17203
+ DEFAULT_LATCH_TERMINAL_SIZE = { cols: 120, rows: 36 };
17204
+ }
17205
+ });
17206
+
17207
+ // ../packages/core/dist/service/latch-session.js
17208
+ import { spawnSync as spawnSync2 } from "node:child_process";
17209
+ function trimmed4(value) {
17210
+ return typeof value === "string" && value.trim() ? value.trim() : null;
17211
+ }
17212
+ function parseState(value) {
17213
+ switch (trimmed4(value)) {
17214
+ case "running":
17215
+ return "running";
17216
+ case "exited":
17217
+ return "exited";
17218
+ case "stopping":
17219
+ return "stopping";
17220
+ case "lost":
17221
+ return "lost";
17222
+ default:
17223
+ return null;
17224
+ }
17225
+ }
17226
+ function runLatchJson({ executable, args }) {
17227
+ const result = spawnSync2(executable, args, {
17228
+ encoding: "utf8",
17229
+ shell: false,
17230
+ timeout: 1e4,
17231
+ maxBuffer: 1024 * 1024
17232
+ });
17233
+ if (result.error) {
17234
+ throw new LatchSessionCommandError(result.error.message);
17235
+ }
17236
+ if (result.status !== 0) {
17237
+ const detail = (result.stderr || result.stdout || `exit ${result.status ?? "unknown"}`).trim().slice(0, 500);
17238
+ throw new LatchSessionCommandError(detail || "Latch command failed.");
17239
+ }
17240
+ try {
17241
+ const parsed = JSON.parse(result.stdout);
17242
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
17243
+ throw new Error("not an object");
17244
+ }
17245
+ return parsed;
17246
+ } catch {
17247
+ throw new LatchSessionCommandError("Latch returned an invalid JSON response.");
17248
+ }
17249
+ }
17250
+ function inspectLatchSession({ executable = "latch", providerSessionId }) {
17251
+ const sessionId = trimmed4(providerSessionId);
17252
+ if (!sessionId)
17253
+ throw new LatchSessionCommandError("A Latch session id is required.");
17254
+ const report = runLatchJson({
17255
+ executable: trimmed4(executable) ?? "latch",
17256
+ args: ["inspect", sessionId, "--json"]
17257
+ });
17258
+ const state = parseState(report.state);
17259
+ if (!state)
17260
+ throw new LatchSessionCommandError("Latch returned an unsupported session state.");
17261
+ const exit = report.exit && typeof report.exit === "object" && !Array.isArray(report.exit) ? report.exit : null;
17262
+ return {
17263
+ providerSessionId: trimmed4(report.id) ?? sessionId,
17264
+ name: trimmed4(report.name) ?? sessionId,
17265
+ state,
17266
+ exitCode: typeof exit?.code === "number" && Number.isFinite(exit.code) ? exit.code : null,
17267
+ inspectedAt: (/* @__PURE__ */ new Date()).toISOString()
17268
+ };
17269
+ }
17270
+ function openLatchSession({ executable = "latch", providerSessionId, viewerKind }) {
17271
+ const sessionId = trimmed4(providerSessionId);
17272
+ if (!sessionId)
17273
+ throw new LatchSessionCommandError("A Latch session id is required.");
17274
+ const viewer = latchViewerFlagForKind(viewerKind);
17275
+ if (!viewer) {
17276
+ throw new LatchSessionCommandError(`Latch cannot open the configured viewer "${viewerKind}".`);
17277
+ }
17278
+ const report = runLatchJson({
17279
+ executable: trimmed4(executable) ?? "latch",
17280
+ args: ["open", sessionId, "--with", viewer, "--json"]
17281
+ });
17282
+ if (report.opened !== true) {
17283
+ throw new LatchSessionCommandError(`Latch did not open the ${viewer} viewer.`);
17284
+ }
17285
+ return {
17286
+ providerSessionId: trimmed4(report.id) ?? sessionId,
17287
+ viewer: trimmed4(report.viewer) ?? viewer,
17288
+ opened: true
17289
+ };
17290
+ }
17291
+ function stopLatchSession({ executable = "latch", providerSessionId }) {
17292
+ const sessionId = trimmed4(providerSessionId);
17293
+ if (!sessionId)
17294
+ throw new LatchSessionCommandError("A Latch session id is required.");
17295
+ const report = runLatchJson({
17296
+ executable: trimmed4(executable) ?? "latch",
17297
+ args: ["stop", sessionId, "--json"]
17298
+ });
17299
+ const state = parseState(report.state);
17300
+ if (!state)
17301
+ throw new LatchSessionCommandError("Latch returned an unsupported session state.");
17302
+ return {
17303
+ providerSessionId: trimmed4(report.id) ?? sessionId,
17304
+ state
17305
+ };
17306
+ }
17307
+ var LatchSessionCommandError;
17308
+ var init_latch_session = __esm({
17309
+ "../packages/core/dist/service/latch-session.js"() {
17310
+ "use strict";
17311
+ init_latch_launch();
17312
+ LatchSessionCommandError = class extends Error {
17313
+ constructor(message) {
17314
+ super(message);
17315
+ this.name = "LatchSessionCommandError";
17316
+ }
17317
+ };
17318
+ }
17319
+ });
17320
+
17321
+ // ../packages/core/dist/service/local-target/git-run.js
17322
+ import { execFileSync as execFileSync4 } from "node:child_process";
16789
17323
  function runGit2(cwd, args) {
16790
17324
  try {
16791
- return execFileSync3("git", args, {
17325
+ return execFileSync4("git", args, {
16792
17326
  cwd,
16793
17327
  encoding: "utf8",
16794
17328
  stdio: ["ignore", "pipe", "ignore"],
@@ -16800,7 +17334,7 @@ function runGit2(cwd, args) {
16800
17334
  }
16801
17335
  function runGitResult(cwd, args) {
16802
17336
  try {
16803
- const stdout = execFileSync3("git", args, {
17337
+ const stdout = execFileSync4("git", args, {
16804
17338
  cwd,
16805
17339
  encoding: "utf8",
16806
17340
  stdio: ["ignore", "pipe", "pipe"],
@@ -16823,13 +17357,13 @@ var init_git_run = __esm({
16823
17357
  });
16824
17358
 
16825
17359
  // ../packages/core/dist/service/local-target/worktree-git.js
16826
- import { existsSync as existsSync16, realpathSync as realpathSync2 } from "node:fs";
16827
- import path17 from "node:path";
17360
+ import { existsSync as existsSync17, realpathSync as realpathSync2 } from "node:fs";
17361
+ import path18 from "node:path";
16828
17362
  function resolveRealPath(targetPath) {
16829
17363
  try {
16830
17364
  return realpathSync2.native(targetPath);
16831
17365
  } catch {
16832
- return path17.resolve(targetPath);
17366
+ return path18.resolve(targetPath);
16833
17367
  }
16834
17368
  }
16835
17369
  function worktreeIsDirty(worktreePath) {
@@ -16859,7 +17393,7 @@ function removeGitWorktree({ primaryRepoPath, worktreePath, force }) {
16859
17393
  args.push(worktreePath);
16860
17394
  runGitResult(primaryRepoPath, args);
16861
17395
  runGitResult(primaryRepoPath, ["worktree", "prune"]);
16862
- return !existsSync16(worktreePath);
17396
+ return !existsSync17(worktreePath);
16863
17397
  }
16864
17398
  function collectManagedWorktrees({ worktreeRoot, projects }) {
16865
17399
  const resolvedRoot = resolveRealPath(worktreeRoot);
@@ -16867,7 +17401,7 @@ function collectManagedWorktrees({ worktreeRoot, projects }) {
16867
17401
  const seen = /* @__PURE__ */ new Set();
16868
17402
  for (const project of projects) {
16869
17403
  const repoPath = project.primaryRepoPath;
16870
- if (!repoPath || !existsSync16(repoPath))
17404
+ if (!repoPath || !existsSync17(repoPath))
16871
17405
  continue;
16872
17406
  const out = runGitResult(repoPath, ["worktree", "list", "--porcelain"]);
16873
17407
  if (!out.ok)
@@ -16878,7 +17412,7 @@ function collectManagedWorktrees({ worktreeRoot, projects }) {
16878
17412
  if (!currentPath)
16879
17413
  return;
16880
17414
  const resolved = resolveRealPath(currentPath);
16881
- const underRoot = resolved === resolvedRoot || resolved.startsWith(resolvedRoot + path17.sep);
17415
+ const underRoot = resolved === resolvedRoot || resolved.startsWith(resolvedRoot + path18.sep);
16882
17416
  if (underRoot && !seen.has(resolved)) {
16883
17417
  seen.add(resolved);
16884
17418
  entries.push({
@@ -16906,7 +17440,7 @@ function collectManagedWorktrees({ worktreeRoot, projects }) {
16906
17440
  return entries;
16907
17441
  }
16908
17442
  function removeManagedWorktree({ path: worktreePath, primaryRepoPath, force }) {
16909
- const target = path17.resolve(worktreePath);
17443
+ const target = path18.resolve(worktreePath);
16910
17444
  if (!force && worktreeIsDirty(target)) {
16911
17445
  return {
16912
17446
  removed: [],
@@ -16920,7 +17454,7 @@ function purgeManagedWorktrees({ entries }) {
16920
17454
  const removed = [];
16921
17455
  const skipped = [];
16922
17456
  for (const entry of entries) {
16923
- const target = path17.resolve(entry.path);
17457
+ const target = path18.resolve(entry.path);
16924
17458
  if (worktreeIsDirty(target)) {
16925
17459
  skipped.push({ path: target, reason: "uncommitted changes" });
16926
17460
  continue;
@@ -16945,10 +17479,10 @@ var init_worktree_git = __esm({
16945
17479
  });
16946
17480
 
16947
17481
  // ../packages/core/dist/service/local-target/branch-actions-git.js
16948
- import { existsSync as existsSync17 } from "node:fs";
17482
+ import { existsSync as existsSync18 } from "node:fs";
16949
17483
  function integrateBranch(input) {
16950
17484
  const { branchName, baseBranch, worktreePath, primaryRepoPath } = input;
16951
- if (!existsSync17(worktreePath)) {
17485
+ if (!existsSync18(worktreePath)) {
16952
17486
  return {
16953
17487
  ok: false,
16954
17488
  code: "BRANCH_NO_WORKTREE",
@@ -17022,15 +17556,15 @@ function integrateBranch(input) {
17022
17556
  }
17023
17557
  function commitBranch(input) {
17024
17558
  const { branchName, worktreePath } = input;
17025
- const trimmed = (input.message ?? "").trim();
17026
- if (!trimmed) {
17559
+ const trimmed5 = (input.message ?? "").trim();
17560
+ if (!trimmed5) {
17027
17561
  return {
17028
17562
  ok: false,
17029
17563
  code: "BRANCH_COMMIT_MESSAGE_REQUIRED",
17030
17564
  message: "A commit message is required."
17031
17565
  };
17032
17566
  }
17033
- if (!existsSync17(worktreePath)) {
17567
+ if (!existsSync18(worktreePath)) {
17034
17568
  return {
17035
17569
  ok: false,
17036
17570
  code: "BRANCH_NO_WORKTREE",
@@ -17062,7 +17596,7 @@ function commitBranch(input) {
17062
17596
  detail: staged.stderr || staged.stdout
17063
17597
  };
17064
17598
  }
17065
- const commit = runGitResult(worktreePath, ["commit", "-m", trimmed]);
17599
+ const commit = runGitResult(worktreePath, ["commit", "-m", trimmed5]);
17066
17600
  if (!commit.ok) {
17067
17601
  return {
17068
17602
  ok: false,
@@ -17086,7 +17620,7 @@ function pushParent(input) {
17086
17620
  };
17087
17621
  }
17088
17622
  let summary = `Pushed ${baseBranch} to origin.`;
17089
- if (existsSync17(worktreePath) && !worktreeIsDirty(worktreePath)) {
17623
+ if (existsSync18(worktreePath) && !worktreeIsDirty(worktreePath)) {
17090
17624
  if (removeGitWorktree({ primaryRepoPath, worktreePath, force: false })) {
17091
17625
  summary += ` Removed the merged worktree for ${branchName}.`;
17092
17626
  }
@@ -17095,7 +17629,7 @@ function pushParent(input) {
17095
17629
  }
17096
17630
  function publishBranch(input) {
17097
17631
  const { branchName, worktreePath, primaryRepoPath } = input;
17098
- const repo = existsSync17(worktreePath) ? worktreePath : primaryRepoPath;
17632
+ const repo = existsSync18(worktreePath) ? worktreePath : primaryRepoPath;
17099
17633
  const push = runGitResult(repo, ["push", "-u", "origin", branchName]);
17100
17634
  if (!push.ok) {
17101
17635
  return {
@@ -17145,7 +17679,7 @@ var init_branch_status_git = __esm({
17145
17679
  });
17146
17680
 
17147
17681
  // ../packages/core/dist/service/local-target/commit-message-diff-git.js
17148
- import { existsSync as existsSync18 } from "node:fs";
17682
+ import { existsSync as existsSync19 } from "node:fs";
17149
17683
  function collectWorktreeChanges(worktreePath) {
17150
17684
  const status = runGitResult(worktreePath, ["status", "--porcelain"]);
17151
17685
  const diff = runGitResult(worktreePath, ["diff", "HEAD"]);
@@ -17161,7 +17695,7 @@ ${diff.stdout}`);
17161
17695
  return sections.join("\n\n");
17162
17696
  }
17163
17697
  function gatherCommitMessageDiff(worktreePath) {
17164
- if (!existsSync18(worktreePath)) {
17698
+ if (!existsSync19(worktreePath)) {
17165
17699
  return {
17166
17700
  ok: false,
17167
17701
  code: "BRANCH_NO_WORKTREE",
@@ -17187,10 +17721,10 @@ var init_commit_message_diff_git = __esm({
17187
17721
  });
17188
17722
 
17189
17723
  // ../packages/core/dist/service/local-target/doctor-checks.js
17190
- import { execFileSync as execFileSync4 } from "node:child_process";
17724
+ import { execFileSync as execFileSync5 } from "node:child_process";
17191
17725
  function commandOnPath(command, args) {
17192
17726
  try {
17193
- const detail = execFileSync4(command, args, {
17727
+ const detail = execFileSync5(command, args, {
17194
17728
  encoding: "utf8",
17195
17729
  stdio: ["ignore", "pipe", "ignore"]
17196
17730
  }).trim();
@@ -17222,12 +17756,15 @@ var init_result = __esm({
17222
17756
  });
17223
17757
 
17224
17758
  // ../packages/core/dist/service/local-target/in-process-provider.js
17225
- import { existsSync as existsSync19 } from "node:fs";
17759
+ import { existsSync as existsSync20 } from "node:fs";
17226
17760
  var InProcessProvider;
17227
17761
  var init_in_process_provider = __esm({
17228
17762
  "../packages/core/dist/service/local-target/in-process-provider.js"() {
17229
17763
  "use strict";
17230
17764
  init_git_tree();
17765
+ init_latch_discovery();
17766
+ init_latch_session();
17767
+ init_terminal_profile_types2();
17231
17768
  init_branch_actions_git();
17232
17769
  init_branch_status_git();
17233
17770
  init_commit_message_diff_git();
@@ -17250,7 +17787,7 @@ var init_in_process_provider = __esm({
17250
17787
  */
17251
17788
  async observeResource(input) {
17252
17789
  const observedAt = (/* @__PURE__ */ new Date()).toISOString();
17253
- const state = existsSync19(input.path) ? "available" : "missing";
17790
+ const state = existsSync20(input.path) ? "available" : "missing";
17254
17791
  return ok(this.target, { state, observedAt });
17255
17792
  }
17256
17793
  /**
@@ -17357,6 +17894,50 @@ var init_in_process_provider = __esm({
17357
17894
  async launchAgent(_input) {
17358
17895
  return fail(this.target, "CAPABILITY_NOT_IMPLEMENTED", "Agent launch is owned by the CLI runner (`ovld runner` / `ovld launch`).");
17359
17896
  }
17897
+ // ---- routed (coo:702) ------------------------------------------------
17898
+ /**
17899
+ * Read-only Latch probe on this machine. In-process is the transport that can
17900
+ * honestly answer it: the provider only exists here when the caller device is
17901
+ * the execution target, so the probe runs where the agent process would run.
17902
+ */
17903
+ async discoverLatch(input) {
17904
+ const executable = input.executable?.trim() || DEFAULT_LATCH_EXECUTABLE;
17905
+ try {
17906
+ const result = discoverLatchForExecutionTarget({
17907
+ // A resolved provider carries the target id; the desktop bridge and dev
17908
+ // proxy do not, so they pass the caller's id to share one cache entry
17909
+ // with the runner probe on the same device.
17910
+ executionTargetId: this.target.executionTargetId ?? (input.executionTargetId?.trim() || "local"),
17911
+ executable,
17912
+ cacheFilePath: defaultLatchDiscoveryCachePath(),
17913
+ force: input.force === true
17914
+ });
17915
+ return ok(this.target, result);
17916
+ } catch (error) {
17917
+ return fail(this.target, "TARGET_OPERATION_FAILED", error instanceof Error ? error.message : "Latch discovery failed on this device.");
17918
+ }
17919
+ }
17920
+ async inspectLatchSession(input) {
17921
+ try {
17922
+ return ok(this.target, inspectLatchSession(input));
17923
+ } catch (error) {
17924
+ return fail(this.target, "TARGET_OPERATION_FAILED", error instanceof Error ? error.message : "Could not inspect the Latch session.");
17925
+ }
17926
+ }
17927
+ async openLatchSession(input) {
17928
+ try {
17929
+ return ok(this.target, openLatchSession(input));
17930
+ } catch (error) {
17931
+ return fail(this.target, "TARGET_OPERATION_FAILED", error instanceof Error ? error.message : "Could not open the Latch session.");
17932
+ }
17933
+ }
17934
+ async stopLatchSession(input) {
17935
+ try {
17936
+ return ok(this.target, stopLatchSession(input));
17937
+ } catch (error) {
17938
+ return fail(this.target, "TARGET_OPERATION_FAILED", error instanceof Error ? error.message : "Could not stop the Latch session.");
17939
+ }
17940
+ }
17360
17941
  async doctor() {
17361
17942
  return ok(this.target, { checks: runLocalTargetDoctorChecks() });
17362
17943
  }
@@ -17497,7 +18078,7 @@ var init_local_target_mutation_runner = __esm({
17497
18078
  });
17498
18079
 
17499
18080
  // ../packages/core/dist/service/project-resource-key.js
17500
- import path18 from "node:path";
18081
+ import path19 from "node:path";
17501
18082
  function deriveProjectResourceKey({ resourceKey, label, directoryPath }) {
17502
18083
  const explicit = resourceKey?.trim();
17503
18084
  if (explicit)
@@ -17505,7 +18086,7 @@ function deriveProjectResourceKey({ resourceKey, label, directoryPath }) {
17505
18086
  const labelKey = label?.trim();
17506
18087
  if (labelKey)
17507
18088
  return slugify(labelKey);
17508
- return slugify(path18.basename(path18.resolve(directoryPath)));
18089
+ return slugify(path19.basename(path19.resolve(directoryPath)));
17509
18090
  }
17510
18091
  var init_project_resource_key = __esm({
17511
18092
  "../packages/core/dist/service/project-resource-key.js"() {
@@ -17515,7 +18096,7 @@ var init_project_resource_key = __esm({
17515
18096
  });
17516
18097
 
17517
18098
  // src/branch-planning.ts
17518
- import path19 from "node:path";
18099
+ import path20 from "node:path";
17519
18100
  function stripCombiningMarks(value) {
17520
18101
  return value.normalize("NFKD").replace(/[\u0300-\u036f]/g, "");
17521
18102
  }
@@ -17548,7 +18129,7 @@ function missionWorktreePath({
17548
18129
  branch
17549
18130
  }) {
17550
18131
  const key = resourceKey.trim() || "project";
17551
- return path19.join(worktreeRoot, projectSlug || "project", key, branchLeaf(branch));
18132
+ return path20.join(worktreeRoot, projectSlug || "project", key, branchLeaf(branch));
17552
18133
  }
17553
18134
  function normalizeRemoteRef(ref) {
17554
18135
  return ref.replace(/^origin\//, "").replace(/^refs\/heads\//, "").replace(/^refs\/remotes\/origin\//, "");
@@ -17622,13 +18203,13 @@ var init_branch_planning = __esm({
17622
18203
  });
17623
18204
 
17624
18205
  // src/branch-preparation.ts
17625
- import { execFileSync as execFileSync5 } from "node:child_process";
17626
- import { existsSync as existsSync20, mkdirSync as mkdirSync9, statSync as statSync4 } from "node:fs";
17627
- import os3 from "node:os";
17628
- import path20 from "node:path";
18206
+ import { execFileSync as execFileSync6 } from "node:child_process";
18207
+ import { existsSync as existsSync21, mkdirSync as mkdirSync10, statSync as statSync5 } from "node:fs";
18208
+ import os4 from "node:os";
18209
+ import path21 from "node:path";
17629
18210
  function runGit3(cwd, args, options = {}) {
17630
18211
  try {
17631
- return execFileSync5("git", args, {
18212
+ return execFileSync6("git", args, {
17632
18213
  cwd,
17633
18214
  encoding: "utf8",
17634
18215
  stdio: ["ignore", "pipe", "pipe"],
@@ -17646,7 +18227,7 @@ function lines(value) {
17646
18227
  function resolveGitRoot2(workingDirectory) {
17647
18228
  const root = runGit3(workingDirectory, ["rev-parse", "--show-toplevel"]);
17648
18229
  if (!root) throw new Error(`${workingDirectory} is not inside a git repository.`);
17649
- return path20.resolve(root);
18230
+ return path21.resolve(root);
17650
18231
  }
17651
18232
  function repoDefaultBranch(gitRoot) {
17652
18233
  const symbolic = runGit3(gitRoot, ["symbolic-ref", "--short", "refs/remotes/origin/HEAD"], {
@@ -17781,9 +18362,9 @@ function missionSequence(mission, missionId) {
17781
18362
  }
17782
18363
  function resolveWorktreeRoot() {
17783
18364
  const override = process.env.OVERLORD_WORKTREE_ROOT?.trim();
17784
- if (override) return path20.resolve(override);
18365
+ if (override) return path21.resolve(override);
17785
18366
  const home = process.env.OVLD_HOME?.trim() || process.env.OVERLORD_HOME?.trim();
17786
- return path20.join(home ? path20.resolve(home) : path20.join(os3.homedir(), ".ovld"), "worktrees");
18367
+ return path21.join(home ? path21.resolve(home) : path21.join(os4.homedir(), ".ovld"), "worktrees");
17787
18368
  }
17788
18369
  function ensureBranchRef(gitRoot, decision) {
17789
18370
  if (decision.action === "reuse") return;
@@ -17794,9 +18375,9 @@ function ensureBranchRef(gitRoot, decision) {
17794
18375
  }
17795
18376
  function ensureWorktree(gitRoot, decision) {
17796
18377
  ensureBranchRef(gitRoot, decision);
17797
- mkdirSync9(path20.dirname(decision.worktreePath), { recursive: true });
17798
- if (existsSync20(decision.worktreePath)) {
17799
- if (!statSync4(decision.worktreePath).isDirectory()) {
18378
+ mkdirSync10(path21.dirname(decision.worktreePath), { recursive: true });
18379
+ if (existsSync21(decision.worktreePath)) {
18380
+ if (!statSync5(decision.worktreePath).isDirectory()) {
17800
18381
  throw new Error(`Worktree path exists and is not a directory: ${decision.worktreePath}`);
17801
18382
  }
17802
18383
  const existingBranch = worktreeBranch(decision.worktreePath);
@@ -17936,7 +18517,7 @@ var init_branch_preparation = __esm({
17936
18517
  });
17937
18518
 
17938
18519
  // src/discover-project-local.ts
17939
- import path21 from "node:path";
18520
+ import path22 from "node:path";
17940
18521
  async function resolvePreferredExecutionTargetId({
17941
18522
  backend
17942
18523
  }) {
@@ -17953,9 +18534,9 @@ function discoverProjectJsonFromFilesystem({
17953
18534
  workingDirectory,
17954
18535
  preferredExecutionTargetId
17955
18536
  }) {
17956
- let current = path21.resolve(workingDirectory);
18537
+ let current = path22.resolve(workingDirectory);
17957
18538
  while (true) {
17958
- const projectJsonPath = path21.join(current, ".overlord", "project.json");
18539
+ const projectJsonPath = path22.join(current, ".overlord", "project.json");
17959
18540
  const raw = readProjectJsonLink(projectJsonPath, { preferredExecutionTargetId });
17960
18541
  if (raw) {
17961
18542
  return {
@@ -17965,7 +18546,7 @@ function discoverProjectJsonFromFilesystem({
17965
18546
  isPrimary: raw.isPrimary
17966
18547
  };
17967
18548
  }
17968
- const parent = path21.dirname(current);
18549
+ const parent = path22.dirname(current);
17969
18550
  if (parent === current) break;
17970
18551
  current = parent;
17971
18552
  }
@@ -17975,16 +18556,16 @@ async function resolveProjectByIdOrName({
17975
18556
  backend,
17976
18557
  projectRef
17977
18558
  }) {
17978
- const trimmed = projectRef.trim();
18559
+ const trimmed5 = projectRef.trim();
17979
18560
  try {
17980
- return await backend.get(`/api/projects/${encodeURIComponent(trimmed)}`);
18561
+ return await backend.get(`/api/projects/${encodeURIComponent(trimmed5)}`);
17981
18562
  } catch (error) {
17982
18563
  if (!(error instanceof CliError) || !/project not found/i.test(error.message)) throw error;
17983
18564
  }
17984
18565
  const projects = await listAccessibleProjects({ backend });
17985
- const match = projects.find((project) => project.name === trimmed) ?? projects.find((project) => project.slug === trimmed);
18566
+ const match = projects.find((project) => project.name === trimmed5) ?? projects.find((project) => project.slug === trimmed5);
17986
18567
  if (!match) {
17987
- throw new CliError({ message: `Project not found: ${trimmed}` });
18568
+ throw new CliError({ message: `Project not found: ${trimmed5}` });
17988
18569
  }
17989
18570
  return match;
17990
18571
  }
@@ -18025,7 +18606,7 @@ async function discoverProjectOnClient({
18025
18606
  const resolvedLocal = localWithTarget ?? local;
18026
18607
  if (!resolvedLocal) {
18027
18608
  throw new CliError({
18028
- message: `No linked Overlord project found for ${path21.resolve(workingDirectory)}. Run \`ovld add-cwd\` or \`ovld create-project\`.`
18609
+ message: `No linked Overlord project found for ${path22.resolve(workingDirectory)}. Run \`ovld add-cwd\` or \`ovld create-project\`.`
18029
18610
  });
18030
18611
  }
18031
18612
  const project = await resolveProjectByIdOrName({ backend, projectRef: resolvedLocal.projectId });
@@ -18045,6 +18626,134 @@ var init_discover_project_local = __esm({
18045
18626
  }
18046
18627
  });
18047
18628
 
18629
+ // src/latch-discovery.ts
18630
+ import path23 from "node:path";
18631
+ function latchDiscoveryCachePath(dataDir = resolveGlobalDataDir()) {
18632
+ return path23.join(dataDir, LATCH_DISCOVERY_CACHE_FILENAME);
18633
+ }
18634
+ function discoverLatchOnThisDevice({
18635
+ executionTargetId,
18636
+ executable = DEFAULT_LATCH_EXECUTABLE,
18637
+ force = false
18638
+ }) {
18639
+ return discoverLatchForExecutionTarget({
18640
+ executionTargetId,
18641
+ executable,
18642
+ cacheFilePath: latchDiscoveryCachePath(),
18643
+ force
18644
+ });
18645
+ }
18646
+ var init_latch_discovery2 = __esm({
18647
+ "src/latch-discovery.ts"() {
18648
+ "use strict";
18649
+ init_latch_discovery();
18650
+ init_terminal_profile_types2();
18651
+ init_config();
18652
+ }
18653
+ });
18654
+
18655
+ // src/latch-launch.ts
18656
+ import { spawnSync as spawnSync3 } from "node:child_process";
18657
+ function spawnLatchJson({
18658
+ executable,
18659
+ args,
18660
+ stdin
18661
+ }) {
18662
+ const result = spawnSync3(executable, args, {
18663
+ encoding: "utf8",
18664
+ input: stdin,
18665
+ env: process.env,
18666
+ maxBuffer: 2 * 1024 * 1024
18667
+ });
18668
+ return {
18669
+ status: result.status,
18670
+ stdout: result.stdout ?? "",
18671
+ stderr: result.stderr ?? ""
18672
+ };
18673
+ }
18674
+ function createLatchSession({
18675
+ executable = DEFAULT_LATCH_EXECUTABLE,
18676
+ commandString,
18677
+ cwd,
18678
+ env,
18679
+ title,
18680
+ name,
18681
+ commandLabel,
18682
+ externalRunId,
18683
+ executionTargetId,
18684
+ shell = process.env.SHELL?.trim() || "/bin/bash"
18685
+ }) {
18686
+ const manifest = buildLatchCreateManifest({
18687
+ commandString,
18688
+ shell,
18689
+ cwd,
18690
+ env,
18691
+ title,
18692
+ name,
18693
+ commandLabel,
18694
+ externalRunId
18695
+ });
18696
+ const result = spawnLatchJson({
18697
+ executable,
18698
+ args: ["create", "--manifest-file", "-", "--json"],
18699
+ stdin: `${JSON.stringify(manifest)}
18700
+ `
18701
+ });
18702
+ if (result.status !== 0) {
18703
+ const detail = (result.stderr || result.stdout || `exit ${result.status ?? "null"}`).trim();
18704
+ throw new Error(`latch create failed: ${detail}`);
18705
+ }
18706
+ const report = parseLatchCreateReport(result.stdout);
18707
+ if (!report) {
18708
+ throw new Error(
18709
+ `latch create returned unusable JSON: ${(result.stdout || result.stderr).trim() || "(empty)"}`
18710
+ );
18711
+ }
18712
+ return {
18713
+ report,
18714
+ providerSession: toExecutionProviderSession({
18715
+ createReport: report,
18716
+ executionTargetId
18717
+ }),
18718
+ executable
18719
+ };
18720
+ }
18721
+ function openLatchViewer({
18722
+ executable = DEFAULT_LATCH_EXECUTABLE,
18723
+ providerSessionId,
18724
+ viewerKind
18725
+ }) {
18726
+ const viewer = latchViewerFlagForKind(viewerKind);
18727
+ const attachCommand = latchAttachCommand({ executable, providerSessionId });
18728
+ if (!viewer) {
18729
+ return {
18730
+ ok: false,
18731
+ warning: `Latch has no viewer for kind "${viewerKind ?? "unknown"}"; session is running \u2014 attach with: ${attachCommand}`,
18732
+ attachCommand
18733
+ };
18734
+ }
18735
+ const result = spawnLatchJson({
18736
+ executable,
18737
+ args: ["open", providerSessionId, "--with", viewer, "--json"]
18738
+ });
18739
+ if (result.status !== 0) {
18740
+ const detail = (result.stderr || result.stdout || `exit ${result.status ?? "null"}`).trim();
18741
+ return {
18742
+ ok: false,
18743
+ warning: `latch open failed (${detail}); session is running \u2014 attach with: ${attachCommand}`,
18744
+ attachCommand
18745
+ };
18746
+ }
18747
+ return { ok: true, viewer };
18748
+ }
18749
+ var init_latch_launch2 = __esm({
18750
+ "src/latch-launch.ts"() {
18751
+ "use strict";
18752
+ init_latch_launch();
18753
+ init_terminal_profile_types2();
18754
+ }
18755
+ });
18756
+
18048
18757
  // src/pre-launch.ts
18049
18758
  function substitutePreLaunchVariables(commands, variables) {
18050
18759
  return commands.map(
@@ -18072,10 +18781,10 @@ function primaryResourcePath(projectResources) {
18072
18781
  for (const entry of projectResources) {
18073
18782
  if (!entry || typeof entry !== "object") continue;
18074
18783
  const record = entry;
18075
- const path32 = typeof record.path === "string" ? record.path.trim() : "";
18076
- if (!path32) continue;
18077
- if (record.isPrimary === true) return path32;
18078
- if (record.isCurrent === true && !currentPath) currentPath = path32;
18784
+ const path34 = typeof record.path === "string" ? record.path.trim() : "";
18785
+ if (!path34) continue;
18786
+ if (record.isPrimary === true) return path34;
18787
+ if (record.isCurrent === true && !currentPath) currentPath = path34;
18079
18788
  }
18080
18789
  return currentPath;
18081
18790
  }
@@ -18175,7 +18884,7 @@ function terminalInnerCommand({
18175
18884
  const invocation = withPreLaunchCommands(agentCommand, preLaunchCommands);
18176
18885
  return `cd ${shellQuote2(workingDirectory)} && ${exports}; ${invocation}`;
18177
18886
  }
18178
- function terminalLaunchScriptContent({
18887
+ function composeAgentTerminalCommand({
18179
18888
  command,
18180
18889
  args,
18181
18890
  workingDirectory,
@@ -18184,8 +18893,25 @@ function terminalLaunchScriptContent({
18184
18893
  preLaunchCommands
18185
18894
  }) {
18186
18895
  const agentCommand = agentShellCommand({ command, args, preCommand });
18896
+ return terminalInnerCommand({ workingDirectory, agentCommand, extraEnv, preLaunchCommands });
18897
+ }
18898
+ function terminalLaunchScriptContent({
18899
+ command,
18900
+ args,
18901
+ workingDirectory,
18902
+ preCommand,
18903
+ extraEnv = {},
18904
+ preLaunchCommands
18905
+ }) {
18187
18906
  return `#!/usr/bin/env bash
18188
- ${terminalInnerCommand({ workingDirectory, agentCommand, extraEnv, preLaunchCommands })}
18907
+ ${composeAgentTerminalCommand({
18908
+ command,
18909
+ args,
18910
+ workingDirectory,
18911
+ preCommand,
18912
+ extraEnv,
18913
+ preLaunchCommands
18914
+ })}
18189
18915
  `;
18190
18916
  }
18191
18917
  function terminalScriptCommand(scriptPath) {
@@ -18426,9 +19152,9 @@ var init_terminal_launcher = __esm({
18426
19152
  });
18427
19153
 
18428
19154
  // src/launch.ts
18429
- import { spawnSync as spawnSync2 } from "node:child_process";
18430
- import { chmodSync as chmodSync4, writeFileSync as writeFileSync8 } from "node:fs";
18431
- import path22 from "node:path";
19155
+ import { spawnSync as spawnSync4 } from "node:child_process";
19156
+ import { chmodSync as chmodSync4, writeFileSync as writeFileSync9 } from "node:fs";
19157
+ import path24 from "node:path";
18432
19158
  function overlordLaunchEnv({
18433
19159
  backendUrl,
18434
19160
  missionId,
@@ -18594,7 +19320,7 @@ function launchScriptPath({
18594
19320
  executionRequestId
18595
19321
  }) {
18596
19322
  const requestPart = executionRequestId ? safeLaunchScriptPart(executionRequestId) : `${process.pid}`;
18597
- return path22.join(tmpDir, `launch-${safeLaunchScriptPart(displayId)}-${requestPart}.sh`);
19323
+ return path24.join(tmpDir, `launch-${safeLaunchScriptPart(displayId)}-${requestPart}.sh`);
18598
19324
  }
18599
19325
  async function buildLaunchPlan({
18600
19326
  runtime,
@@ -18603,12 +19329,12 @@ async function buildLaunchPlan({
18603
19329
  const context = await loadMissionContext({ runtime, missionId: options.missionId });
18604
19330
  pruneStaleProjectTmp({ workingDirectory: options.workingDirectory, create: true });
18605
19331
  const tmpDir = ensureProjectTmpDir(options.workingDirectory);
18606
- const contextFile = path22.join(
19332
+ const contextFile = path24.join(
18607
19333
  tmpDir,
18608
19334
  `mission-${context.displayId.replace(/[^a-zA-Z0-9_-]/g, "-")}.md`
18609
19335
  );
18610
19336
  const launchContext = context.launchContext;
18611
- writeFileSync8(contextFile, `${launchContext}
19337
+ writeFileSync9(contextFile, `${launchContext}
18612
19338
  `);
18613
19339
  const projectResources = await loadProjectResourcesForLaunch({
18614
19340
  runtime,
@@ -18653,13 +19379,21 @@ async function buildLaunchPlan({
18653
19379
  contextFile,
18654
19380
  launchMessage: `Attach to ovld mission ${context.displayId}, then immediately execute ${context.title}. Do not wait for more instructions.`
18655
19381
  });
19382
+ const latchCommandString = composeAgentTerminalCommand({
19383
+ command: command.command,
19384
+ args: command.args,
19385
+ workingDirectory: options.workingDirectory,
19386
+ preCommand: options.preCommand,
19387
+ extraEnv: exportedEnv,
19388
+ preLaunchCommands
19389
+ });
18656
19390
  const terminalScriptPath = options.terminalLauncher?.trim() ? launchScriptPath({
18657
19391
  tmpDir,
18658
19392
  displayId: context.displayId,
18659
19393
  executionRequestId: options.executionRequestId
18660
19394
  }) : null;
18661
19395
  if (terminalScriptPath) {
18662
- writeFileSync8(
19396
+ writeFileSync9(
18663
19397
  terminalScriptPath,
18664
19398
  terminalLaunchScriptContent({
18665
19399
  command: command.command,
@@ -18691,7 +19425,11 @@ async function buildLaunchPlan({
18691
19425
  contextFile,
18692
19426
  workingDirectory: options.workingDirectory,
18693
19427
  execution,
18694
- env: exportedEnv
19428
+ env: exportedEnv,
19429
+ latchCommandString,
19430
+ launchSession: options.launchSession ?? null,
19431
+ missionTitle: options.missionTitle ?? context.title,
19432
+ missionDisplayId: options.missionDisplayId ?? context.displayId
18695
19433
  };
18696
19434
  }
18697
19435
  async function launchAgent({
@@ -18707,26 +19445,126 @@ async function launchAgent({
18707
19445
  ...tmpEnvFor(options.workingDirectory),
18708
19446
  ...plan.env
18709
19447
  };
19448
+ const snapshot = options.launchSession ?? plan.launchSession ?? null;
19449
+ const providerKind = snapshot?.executionProvider.kind ?? "direct";
19450
+ const executable = snapshot?.executionProvider.executable ?? "latch";
19451
+ let providerFallbackWarning = null;
19452
+ let useLatch = false;
19453
+ const existingProviderSession = providerKind === "latch" ? existingLatchProviderSession({
19454
+ latchSessionId: process.env.LATCH_SESSION_ID,
19455
+ executionTargetId: options.executionTargetId
19456
+ }) : null;
19457
+ if (existingProviderSession && plan.latchCommandString) {
19458
+ const shell = process.env.SHELL?.trim() || "/bin/bash";
19459
+ const result2 = spawnSync4(shell, ["-lc", plan.latchCommandString], {
19460
+ cwd: options.workingDirectory,
19461
+ env,
19462
+ stdio: "inherit"
19463
+ });
19464
+ return {
19465
+ plan: {
19466
+ ...plan,
19467
+ execution: {
19468
+ command: shell,
19469
+ args: ["-lc", plan.latchCommandString],
19470
+ useShell: false,
19471
+ terminal: null,
19472
+ display: `Latch session ${existingProviderSession.providerSessionId} (inline) \u203A ${plan.latchCommandString}`
19473
+ }
19474
+ },
19475
+ status: result2.status,
19476
+ signal: result2.signal,
19477
+ providerSession: existingProviderSession,
19478
+ viewerOpen: null,
19479
+ providerFallbackWarning
19480
+ };
19481
+ }
19482
+ if (providerKind === "latch") {
19483
+ if (!options.executionTargetId) {
19484
+ providerFallbackWarning = "Latch provider selected but no execution target id is available; falling back to direct launch.";
19485
+ } else {
19486
+ const discovery = discoverLatchOnThisDevice({
19487
+ executionTargetId: options.executionTargetId,
19488
+ executable
19489
+ });
19490
+ useLatch = shouldUseLatchProvider({
19491
+ providerKind,
19492
+ latchSelectable: discovery.latchSelectable
19493
+ });
19494
+ if (!useLatch) {
19495
+ 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.";
19496
+ }
19497
+ }
19498
+ }
19499
+ if (useLatch && plan.latchCommandString) {
19500
+ const created = createLatchSession({
19501
+ executable,
19502
+ commandString: plan.latchCommandString,
19503
+ cwd: options.workingDirectory,
19504
+ env: plan.env,
19505
+ title: plan.missionTitle,
19506
+ name: plan.missionDisplayId,
19507
+ commandLabel: options.agent,
19508
+ externalRunId: options.executionRequestId,
19509
+ executionTargetId: options.executionTargetId
19510
+ });
19511
+ let viewerOpen = null;
19512
+ const openOnLaunch = snapshot?.viewer.openOnLaunch !== false;
19513
+ if (openOnLaunch) {
19514
+ viewerOpen = openLatchViewer({
19515
+ executable,
19516
+ providerSessionId: created.providerSession.providerSessionId,
19517
+ viewerKind: snapshot?.viewer.kind ?? "iterm"
19518
+ });
19519
+ }
19520
+ return {
19521
+ plan: {
19522
+ ...plan,
19523
+ execution: {
19524
+ command: executable,
19525
+ args: ["create", "--manifest-file", "-", "--json"],
19526
+ useShell: false,
19527
+ terminal: snapshot?.viewer.launcher ?? null,
19528
+ display: `latch create \u203A ${plan.latchCommandString}`
19529
+ }
19530
+ },
19531
+ status: 0,
19532
+ signal: null,
19533
+ providerSession: created.providerSession,
19534
+ viewerOpen,
19535
+ providerFallbackWarning
19536
+ };
19537
+ }
18710
19538
  const { execution } = plan;
18711
- const result = execution.useShell ? spawnSync2(execution.command, {
19539
+ const result = execution.useShell ? spawnSync4(execution.command, {
18712
19540
  cwd: options.workingDirectory,
18713
19541
  env,
18714
19542
  shell: true,
18715
19543
  stdio: "inherit"
18716
- }) : spawnSync2(execution.command, execution.args, {
19544
+ }) : spawnSync4(execution.command, execution.args, {
18717
19545
  cwd: options.workingDirectory,
18718
19546
  env,
18719
19547
  stdio: "inherit"
18720
19548
  });
18721
- return { plan, status: result.status, signal: result.signal };
19549
+ return {
19550
+ plan,
19551
+ status: result.status,
19552
+ signal: result.signal,
19553
+ providerSession: null,
19554
+ viewerOpen: null,
19555
+ providerFallbackWarning
19556
+ };
18722
19557
  }
18723
19558
  var AGENT_HISTORY_EXCLUDED_EVENT_TYPES, EXECUTION_DIRECTIVE;
18724
19559
  var init_launch = __esm({
18725
19560
  "src/launch.ts"() {
18726
19561
  "use strict";
18727
19562
  init_dist2();
19563
+ init_latch_launch();
18728
19564
  init_channel();
18729
19565
  init_agent_binaries();
19566
+ init_latch_discovery2();
19567
+ init_latch_launch2();
18730
19568
  init_pre_launch();
18731
19569
  init_project_tmp();
18732
19570
  init_terminal_launcher();
@@ -18740,8 +19578,8 @@ var init_launch = __esm({
18740
19578
  });
18741
19579
 
18742
19580
  // src/launch-bootstrap.ts
18743
- import { existsSync as existsSync21, readdirSync as readdirSync4, readFileSync as readFileSync15, statSync as statSync5 } from "node:fs";
18744
- import path23 from "node:path";
19581
+ import { existsSync as existsSync22, readdirSync as readdirSync4, readFileSync as readFileSync16, statSync as statSync6 } from "node:fs";
19582
+ import path25 from "node:path";
18745
19583
  function firstCapture(match) {
18746
19584
  if (!match) return null;
18747
19585
  const value = match[1] ?? match[2] ?? match[3] ?? null;
@@ -18762,15 +19600,15 @@ function recoverLaunchBootstrapFromProjectTmp({
18762
19600
  const trimmedMission = missionId.trim();
18763
19601
  if (!trimmedMission) return empty;
18764
19602
  const tmpDir = projectTmpDir(workingDirectory);
18765
- if (!existsSync21(tmpDir)) return empty;
19603
+ if (!existsSync22(tmpDir)) return empty;
18766
19604
  const prefix = `launch-${safeMissionPart(trimmedMission)}-`;
18767
19605
  let newest = null;
18768
19606
  try {
18769
19607
  for (const name of readdirSync4(tmpDir)) {
18770
19608
  if (!name.startsWith(prefix) || !name.endsWith(".sh")) continue;
18771
- const filePath = path23.join(tmpDir, name);
19609
+ const filePath = path25.join(tmpDir, name);
18772
19610
  try {
18773
- const mtimeMs = statSync5(filePath).mtimeMs;
19611
+ const mtimeMs = statSync6(filePath).mtimeMs;
18774
19612
  if (!newest || mtimeMs > newest.mtimeMs) {
18775
19613
  newest = { path: filePath, mtimeMs };
18776
19614
  }
@@ -18783,7 +19621,7 @@ function recoverLaunchBootstrapFromProjectTmp({
18783
19621
  if (!newest) return empty;
18784
19622
  let contents = "";
18785
19623
  try {
18786
- contents = readFileSync15(newest.path, "utf8");
19624
+ contents = readFileSync16(newest.path, "utf8");
18787
19625
  } catch {
18788
19626
  return empty;
18789
19627
  }
@@ -18804,8 +19642,8 @@ var init_launch_bootstrap = __esm({
18804
19642
  });
18805
19643
 
18806
19644
  // src/org-setup.ts
18807
- import { readFileSync as readFileSync16 } from "node:fs";
18808
- import path24 from "node:path";
19645
+ import { readFileSync as readFileSync17 } from "node:fs";
19646
+ import path26 from "node:path";
18809
19647
  import { createInterface as createInterface3 } from "node:readline";
18810
19648
  function suggestSlug(name) {
18811
19649
  const cleaned = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
@@ -18820,8 +19658,8 @@ function promptText({
18820
19658
  return new Promise((resolve) => {
18821
19659
  rl.question(`${question}${suffix}: `, (answer) => {
18822
19660
  rl.close();
18823
- const trimmed = answer.trim();
18824
- resolve(trimmed || defaultValue || "");
19661
+ const trimmed5 = answer.trim();
19662
+ resolve(trimmed5 || defaultValue || "");
18825
19663
  });
18826
19664
  });
18827
19665
  }
@@ -18884,12 +19722,12 @@ async function runOrgSetupCommand({
18884
19722
  let logoWarning = null;
18885
19723
  if (logoPath) {
18886
19724
  try {
18887
- const resolvedPath = path24.resolve(logoPath);
18888
- const bytes = readFileSync16(resolvedPath);
19725
+ const resolvedPath = path26.resolve(logoPath);
19726
+ const bytes = readFileSync17(resolvedPath);
18889
19727
  const stored = await runtime.backend.postRaw({
18890
19728
  path: "/api/uploads/organization-images",
18891
19729
  body: bytes,
18892
- filename: path24.basename(resolvedPath)
19730
+ filename: path26.basename(resolvedPath)
18893
19731
  });
18894
19732
  await runtime.backend.patch({
18895
19733
  path: `/api/organizations/${encodeURIComponent(organization.id)}`,
@@ -19384,17 +20222,17 @@ var init_protocol_help = __esm({
19384
20222
 
19385
20223
  // src/vcs-sessions.ts
19386
20224
  import { createHash as createHash8 } from "node:crypto";
19387
- import { existsSync as existsSync22, mkdirSync as mkdirSync10, readFileSync as readFileSync17, writeFileSync as writeFileSync9 } from "node:fs";
19388
- import path25 from "node:path";
20225
+ import { existsSync as existsSync23, mkdirSync as mkdirSync11, readFileSync as readFileSync18, writeFileSync as writeFileSync10 } from "node:fs";
20226
+ import path27 from "node:path";
19389
20227
  function manifestPath2(workingDirectory) {
19390
- const key = createHash8("sha256").update(path25.resolve(workingDirectory)).digest("hex");
19391
- return path25.join(resolveGlobalDataDir(), "vcs-sessions", `${key}.json`);
20228
+ const key = createHash8("sha256").update(path27.resolve(workingDirectory)).digest("hex");
20229
+ return path27.join(resolveGlobalDataDir(), "vcs-sessions", `${key}.json`);
19392
20230
  }
19393
20231
  function readEntries(workingDirectory) {
19394
20232
  try {
19395
20233
  const target = manifestPath2(workingDirectory);
19396
- if (!existsSync22(target)) return [];
19397
- const raw = JSON.parse(readFileSync17(target, "utf8"));
20234
+ if (!existsSync23(target)) return [];
20235
+ const raw = JSON.parse(readFileSync18(target, "utf8"));
19398
20236
  if (!Array.isArray(raw.entries)) return [];
19399
20237
  const now = Date.now();
19400
20238
  return raw.entries.flatMap((entry) => {
@@ -19413,8 +20251,8 @@ function readEntries(workingDirectory) {
19413
20251
  function writeEntries(workingDirectory, entries) {
19414
20252
  try {
19415
20253
  const target = manifestPath2(workingDirectory);
19416
- mkdirSync10(path25.dirname(target), { recursive: true });
19417
- writeFileSync9(target, JSON.stringify({ entries }));
20254
+ mkdirSync11(path27.dirname(target), { recursive: true });
20255
+ writeFileSync10(target, JSON.stringify({ entries }));
19418
20256
  } catch {
19419
20257
  }
19420
20258
  }
@@ -19464,23 +20302,23 @@ var init_vcs_sessions = __esm({
19464
20302
  });
19465
20303
 
19466
20304
  // src/vcs.ts
19467
- import { execFileSync as execFileSync6 } from "node:child_process";
20305
+ import { execFileSync as execFileSync7 } from "node:child_process";
19468
20306
  import { createHash as createHash9 } from "node:crypto";
19469
20307
  import {
19470
- existsSync as existsSync23,
19471
- mkdirSync as mkdirSync11,
20308
+ existsSync as existsSync24,
20309
+ mkdirSync as mkdirSync12,
19472
20310
  readdirSync as readdirSync5,
19473
- readFileSync as readFileSync18,
20311
+ readFileSync as readFileSync19,
19474
20312
  realpathSync as realpathSync3,
19475
20313
  rmSync as rmSync5,
19476
- writeFileSync as writeFileSync10
20314
+ writeFileSync as writeFileSync11
19477
20315
  } from "node:fs";
19478
- import path26 from "node:path";
20316
+ import path28 from "node:path";
19479
20317
  function normalizePath(filePath) {
19480
20318
  return filePath.replace(/\\/g, "/").trim();
19481
20319
  }
19482
20320
  function sameWorkingDirectory(left, right) {
19483
- return typeof left === "string" && path26.resolve(left) === path26.resolve(right);
20321
+ return typeof left === "string" && path28.resolve(left) === path28.resolve(right);
19484
20322
  }
19485
20323
  function parsePorcelainLine(line) {
19486
20324
  const trimmedEnd = line.replace(/\s+$/, "");
@@ -19500,7 +20338,7 @@ function hashWorktreeFile({
19500
20338
  filePath
19501
20339
  }) {
19502
20340
  try {
19503
- return execFileSync6("git", ["hash-object", filePath], {
20341
+ return execFileSync7("git", ["hash-object", filePath], {
19504
20342
  cwd: workingDirectory,
19505
20343
  encoding: "utf8",
19506
20344
  stdio: ["ignore", "pipe", "ignore"]
@@ -19511,7 +20349,7 @@ function hashWorktreeFile({
19511
20349
  }
19512
20350
  function readChangedFiles(workingDirectory) {
19513
20351
  try {
19514
- const output = execFileSync6("git", ["status", "--porcelain"], {
20352
+ const output = execFileSync7("git", ["status", "--porcelain"], {
19515
20353
  cwd: workingDirectory,
19516
20354
  encoding: "utf8",
19517
20355
  stdio: ["ignore", "pipe", "ignore"],
@@ -19531,13 +20369,13 @@ function sessionKeyHash({
19531
20369
  workingDirectory,
19532
20370
  missionId
19533
20371
  }) {
19534
- return createHash9("sha256").update(`${path26.resolve(workingDirectory)}\0${missionId}`).digest("hex");
20372
+ return createHash9("sha256").update(`${path28.resolve(workingDirectory)}\0${missionId}`).digest("hex");
19535
20373
  }
19536
20374
  function baselineFilePath({
19537
20375
  workingDirectory,
19538
20376
  missionId
19539
20377
  }) {
19540
- return path26.join(
20378
+ return path28.join(
19541
20379
  resolveGlobalDataDir(),
19542
20380
  "vcs-baselines",
19543
20381
  `${sessionKeyHash({ workingDirectory, missionId })}.json`
@@ -19547,7 +20385,7 @@ function touchedFilesPath({
19547
20385
  workingDirectory,
19548
20386
  missionId
19549
20387
  }) {
19550
- return path26.join(
20388
+ return path28.join(
19551
20389
  resolveGlobalDataDir(),
19552
20390
  "vcs-touched",
19553
20391
  `${sessionKeyHash({ workingDirectory, missionId })}.json`
@@ -19557,7 +20395,7 @@ function rationaleNotesPath({
19557
20395
  workingDirectory,
19558
20396
  missionId
19559
20397
  }) {
19560
- return path26.join(
20398
+ return path28.join(
19561
20399
  resolveGlobalDataDir(),
19562
20400
  "vcs-rationale-notes",
19563
20401
  `${sessionKeyHash({ workingDirectory, missionId })}.json`
@@ -19567,7 +20405,7 @@ function bashSnapshotPath({
19567
20405
  workingDirectory,
19568
20406
  missionId
19569
20407
  }) {
19570
- return path26.join(
20408
+ return path28.join(
19571
20409
  resolveGlobalDataDir(),
19572
20410
  "vcs-touched",
19573
20411
  `${sessionKeyHash({ workingDirectory, missionId })}.bash-snapshot.json`
@@ -19579,8 +20417,8 @@ function readBashSnapshot({
19579
20417
  }) {
19580
20418
  try {
19581
20419
  const target = bashSnapshotPath({ workingDirectory, missionId });
19582
- if (!existsSync23(target)) return /* @__PURE__ */ new Map();
19583
- const raw = JSON.parse(readFileSync18(target, "utf8"));
20420
+ if (!existsSync24(target)) return /* @__PURE__ */ new Map();
20421
+ const raw = JSON.parse(readFileSync19(target, "utf8"));
19584
20422
  const byPath = /* @__PURE__ */ new Map();
19585
20423
  if (Array.isArray(raw.files)) {
19586
20424
  for (const entry of raw.files) {
@@ -19605,8 +20443,8 @@ function writeBashSnapshot({
19605
20443
  }) {
19606
20444
  try {
19607
20445
  const target = bashSnapshotPath({ workingDirectory, missionId });
19608
- mkdirSync11(path26.dirname(target), { recursive: true });
19609
- writeFileSync10(target, JSON.stringify({ updatedAt: (/* @__PURE__ */ new Date()).toISOString(), files }));
20446
+ mkdirSync12(path28.dirname(target), { recursive: true });
20447
+ writeFileSync11(target, JSON.stringify({ updatedAt: (/* @__PURE__ */ new Date()).toISOString(), files }));
19610
20448
  } catch {
19611
20449
  }
19612
20450
  }
@@ -19639,12 +20477,12 @@ function recordBashObservedChanges({
19639
20477
  }
19640
20478
  }
19641
20479
  function normalizeAbsolute(filePath) {
19642
- const resolved = path26.resolve(filePath);
20480
+ const resolved = path28.resolve(filePath);
19643
20481
  try {
19644
20482
  return realpathSync3(resolved).replace(/\\/g, "/");
19645
20483
  } catch {
19646
20484
  try {
19647
- return path26.join(realpathSync3(path26.dirname(resolved)), path26.basename(resolved)).replace(/\\/g, "/");
20485
+ return path28.join(realpathSync3(path28.dirname(resolved)), path28.basename(resolved)).replace(/\\/g, "/");
19648
20486
  } catch {
19649
20487
  return resolved.replace(/\\/g, "/");
19650
20488
  }
@@ -19652,7 +20490,7 @@ function normalizeAbsolute(filePath) {
19652
20490
  }
19653
20491
  function gitRepoRoot(workingDirectory) {
19654
20492
  try {
19655
- const root = execFileSync6("git", ["rev-parse", "--show-toplevel"], {
20493
+ const root = execFileSync7("git", ["rev-parse", "--show-toplevel"], {
19656
20494
  cwd: workingDirectory,
19657
20495
  encoding: "utf8",
19658
20496
  stdio: ["ignore", "pipe", "ignore"]
@@ -19671,7 +20509,7 @@ function resetTouchedFiles({
19671
20509
  touchedFilesPath({ workingDirectory, missionId }),
19672
20510
  bashSnapshotPath({ workingDirectory, missionId })
19673
20511
  ]) {
19674
- if (existsSync23(target)) rmSync5(target);
20512
+ if (existsSync24(target)) rmSync5(target);
19675
20513
  }
19676
20514
  } catch {
19677
20515
  }
@@ -19682,14 +20520,14 @@ function resetRationaleNotes({
19682
20520
  }) {
19683
20521
  try {
19684
20522
  const target = rationaleNotesPath({ workingDirectory, missionId });
19685
- if (existsSync23(target)) rmSync5(target);
20523
+ if (existsSync24(target)) rmSync5(target);
19686
20524
  } catch {
19687
20525
  }
19688
20526
  }
19689
20527
  function truncateNoteText(value, max = 500) {
19690
- const trimmed = (value ?? "").replace(/\s+/g, " ").trim();
19691
- if (!trimmed) return null;
19692
- return trimmed.length > max ? `${trimmed.slice(0, max - 1)}...` : trimmed;
20528
+ const trimmed5 = (value ?? "").replace(/\s+/g, " ").trim();
20529
+ if (!trimmed5) return null;
20530
+ return trimmed5.length > max ? `${trimmed5.slice(0, max - 1)}...` : trimmed5;
19693
20531
  }
19694
20532
  function readRationaleNotes({
19695
20533
  workingDirectory,
@@ -19697,8 +20535,8 @@ function readRationaleNotes({
19697
20535
  }) {
19698
20536
  try {
19699
20537
  const target = rationaleNotesPath({ workingDirectory, missionId });
19700
- if (!existsSync23(target)) return [];
19701
- const raw = JSON.parse(readFileSync18(target, "utf8"));
20538
+ if (!existsSync24(target)) return [];
20539
+ const raw = JSON.parse(readFileSync19(target, "utf8"));
19702
20540
  if (!Array.isArray(raw.notes)) return [];
19703
20541
  return raw.notes.flatMap((note) => {
19704
20542
  if (typeof note !== "object" || note === null || typeof note.filePath !== "string") {
@@ -19732,7 +20570,7 @@ function recordRationaleNotes({
19732
20570
  intent: truncateNoteText(note.intent),
19733
20571
  transcriptContext: truncateNoteText(note.transcriptContext)
19734
20572
  })).filter((note) => note.filePath).map((note) => {
19735
- const absolute = normalizeAbsolute(path26.resolve(workingDirectory, note.filePath));
20573
+ const absolute = normalizeAbsolute(path28.resolve(workingDirectory, note.filePath));
19736
20574
  return {
19737
20575
  filePath: absolute,
19738
20576
  toolName: note.toolName,
@@ -19740,17 +20578,17 @@ function recordRationaleNotes({
19740
20578
  transcriptContext: note.transcriptContext,
19741
20579
  contentHash: hashWorktreeFile({
19742
20580
  workingDirectory,
19743
- filePath: path26.relative(workingDirectory, absolute)
20581
+ filePath: path28.relative(workingDirectory, absolute)
19744
20582
  }),
19745
20583
  recordedAt: (/* @__PURE__ */ new Date()).toISOString()
19746
20584
  };
19747
20585
  });
19748
20586
  if (additions.length === 0) return;
19749
20587
  const target = rationaleNotesPath({ workingDirectory, missionId });
19750
- mkdirSync11(path26.dirname(target), { recursive: true });
20588
+ mkdirSync12(path28.dirname(target), { recursive: true });
19751
20589
  const prior = readRationaleNotes({ workingDirectory, missionId });
19752
20590
  const notesToKeep = [...prior, ...additions].slice(-200);
19753
- writeFileSync10(
20591
+ writeFileSync11(
19754
20592
  target,
19755
20593
  JSON.stringify({ updatedAt: (/* @__PURE__ */ new Date()).toISOString(), notes: notesToKeep })
19756
20594
  );
@@ -19763,16 +20601,16 @@ function recordTouchedFiles({
19763
20601
  files
19764
20602
  }) {
19765
20603
  try {
19766
- const additions = files.map((filePath) => (filePath ?? "").trim()).filter(Boolean).map((filePath) => normalizeAbsolute(path26.resolve(workingDirectory, filePath)));
20604
+ const additions = files.map((filePath) => (filePath ?? "").trim()).filter(Boolean).map((filePath) => normalizeAbsolute(path28.resolve(workingDirectory, filePath)));
19767
20605
  if (additions.length === 0) return;
19768
20606
  const target = touchedFilesPath({ workingDirectory, missionId });
19769
- mkdirSync11(path26.dirname(target), { recursive: true });
20607
+ mkdirSync12(path28.dirname(target), { recursive: true });
19770
20608
  const existing = readTouchedLog({ workingDirectory, missionId })?.paths ?? /* @__PURE__ */ new Set();
19771
20609
  for (const filePath of additions) existing.add(filePath);
19772
- writeFileSync10(
20610
+ writeFileSync11(
19773
20611
  target,
19774
20612
  JSON.stringify({
19775
- workingDirectory: path26.resolve(workingDirectory),
20613
+ workingDirectory: path28.resolve(workingDirectory),
19776
20614
  missionId,
19777
20615
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
19778
20616
  paths: Array.from(existing)
@@ -19785,7 +20623,7 @@ function hasTouchedFilesLog({
19785
20623
  workingDirectory,
19786
20624
  missionId
19787
20625
  }) {
19788
- return existsSync23(touchedFilesPath({ workingDirectory, missionId }));
20626
+ return existsSync24(touchedFilesPath({ workingDirectory, missionId }));
19789
20627
  }
19790
20628
  function readTouchedLog({
19791
20629
  workingDirectory,
@@ -19793,8 +20631,8 @@ function readTouchedLog({
19793
20631
  }) {
19794
20632
  try {
19795
20633
  const target = touchedFilesPath({ workingDirectory, missionId });
19796
- if (!existsSync23(target)) return null;
19797
- const raw = JSON.parse(readFileSync18(target, "utf8"));
20634
+ if (!existsSync24(target)) return null;
20635
+ const raw = JSON.parse(readFileSync19(target, "utf8"));
19798
20636
  const result = /* @__PURE__ */ new Set();
19799
20637
  if (Array.isArray(raw.paths)) {
19800
20638
  for (const entry of raw.paths) {
@@ -19827,14 +20665,14 @@ function writeBaseline({
19827
20665
  }) {
19828
20666
  try {
19829
20667
  const target = baselineFilePath({ workingDirectory, missionId });
19830
- mkdirSync11(path26.dirname(target), { recursive: true });
20668
+ mkdirSync12(path28.dirname(target), { recursive: true });
19831
20669
  const snapshot = {
19832
- workingDirectory: path26.resolve(workingDirectory),
20670
+ workingDirectory: path28.resolve(workingDirectory),
19833
20671
  missionId,
19834
20672
  capturedAt: (/* @__PURE__ */ new Date()).toISOString(),
19835
20673
  files: snapshotBaselineFiles({ workingDirectory, files })
19836
20674
  };
19837
- writeFileSync10(target, JSON.stringify(snapshot));
20675
+ writeFileSync11(target, JSON.stringify(snapshot));
19838
20676
  } catch {
19839
20677
  }
19840
20678
  }
@@ -19846,13 +20684,13 @@ function readPeerTouchedClaims({
19846
20684
  readActiveSessions(workingDirectory).map((entry) => entry.missionId.trim()).filter(Boolean)
19847
20685
  );
19848
20686
  if (activeMissionIds.size === 0) return [];
19849
- const directory = path26.join(resolveGlobalDataDir(), "vcs-touched");
19850
- if (!existsSync23(directory)) return [];
20687
+ const directory = path28.join(resolveGlobalDataDir(), "vcs-touched");
20688
+ if (!existsSync24(directory)) return [];
19851
20689
  const claims = [];
19852
20690
  for (const name of readdirSync5(directory)) {
19853
20691
  if (!name.endsWith(".json") || name.endsWith(".bash-snapshot.json")) continue;
19854
20692
  try {
19855
- const raw = JSON.parse(readFileSync18(path26.join(directory, name), "utf8"));
20693
+ const raw = JSON.parse(readFileSync19(path28.join(directory, name), "utf8"));
19856
20694
  const candidateMissionId = typeof raw.missionId === "string" && raw.missionId.trim() ? raw.missionId.trim() : null;
19857
20695
  if (!candidateMissionId || candidateMissionId === missionId) continue;
19858
20696
  if (!activeMissionIds.has(candidateMissionId)) continue;
@@ -19877,8 +20715,8 @@ function readBaselineSnapshot({
19877
20715
  }) {
19878
20716
  try {
19879
20717
  const target = baselineFilePath({ workingDirectory, missionId });
19880
- if (!existsSync23(target)) return /* @__PURE__ */ new Map();
19881
- const raw = JSON.parse(readFileSync18(target, "utf8"));
20718
+ if (!existsSync24(target)) return /* @__PURE__ */ new Map();
20719
+ const raw = JSON.parse(readFileSync19(target, "utf8"));
19882
20720
  if (Array.isArray(raw.files)) {
19883
20721
  const byPath = /* @__PURE__ */ new Map();
19884
20722
  for (const entry of raw.files) {
@@ -19972,10 +20810,10 @@ function compileIgnorePattern(rawPattern) {
19972
20810
  }
19973
20811
  function loadIgnoreRules(repoRoot) {
19974
20812
  try {
19975
- const target = path26.join(repoRoot, OVERLORD_IGNORE_FILENAME);
19976
- if (!existsSync23(target)) return [];
20813
+ const target = path28.join(repoRoot, OVERLORD_IGNORE_FILENAME);
20814
+ if (!existsSync24(target)) return [];
19977
20815
  const rules = [];
19978
- for (const rawLine of readFileSync18(target, "utf8").split("\n")) {
20816
+ for (const rawLine of readFileSync19(target, "utf8").split("\n")) {
19979
20817
  const line = rawLine.replace(/\r$/, "").trim();
19980
20818
  if (!line || line.startsWith("#")) continue;
19981
20819
  const rule = compileIgnorePattern(line);
@@ -20009,7 +20847,7 @@ function filterRunAttributableChanges({
20009
20847
  return [];
20010
20848
  }
20011
20849
  if (!touched) return [{ filePath: entry.filePath, vcsStatus: entry.vcsStatus }];
20012
- const absolute = normalizeAbsolute(path26.resolve(repoRoot, entry.filePath));
20850
+ const absolute = normalizeAbsolute(path28.resolve(repoRoot, entry.filePath));
20013
20851
  if (touched.paths.has(absolute)) {
20014
20852
  return [
20015
20853
  {
@@ -20040,7 +20878,7 @@ function filterRunAttributableChanges({
20040
20878
  });
20041
20879
  }
20042
20880
  function titleFromPath(filePath) {
20043
- const base = path26.basename(filePath).replace(/\.[^.]+$/, "");
20881
+ const base = path28.basename(filePath).replace(/\.[^.]+$/, "");
20044
20882
  const words = base.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[-_]+/g, " ").trim();
20045
20883
  if (!words) return `Update ${filePath}`;
20046
20884
  return `Update ${words.replace(/\b\w/g, (char) => char.toUpperCase())}`;
@@ -20063,7 +20901,7 @@ function draftChangeRationalesFromNotes({
20063
20901
  if (notes.length === 0 || files.length === 0) return [];
20064
20902
  const repoRoot = gitRepoRoot(workingDirectory) ?? workingDirectory;
20065
20903
  return files.flatMap((file) => {
20066
- const absolute = normalizeAbsolute(path26.resolve(repoRoot, file.filePath));
20904
+ const absolute = normalizeAbsolute(path28.resolve(repoRoot, file.filePath));
20067
20905
  const currentHash = hashWorktreeFile({ workingDirectory, filePath: file.filePath });
20068
20906
  const note = latestRelevantNote({ notes, filePath: absolute, currentHash });
20069
20907
  if (!note) return [];
@@ -20103,17 +20941,17 @@ var init_vcs = __esm({
20103
20941
  });
20104
20942
 
20105
20943
  // src/record-touched.ts
20106
- import { readFileSync as readFileSync19 } from "node:fs";
20107
- import path27 from "node:path";
20944
+ import { readFileSync as readFileSync20 } from "node:fs";
20945
+ import path29 from "node:path";
20108
20946
  function collectCandidates(toolInput) {
20109
20947
  const counts = /* @__PURE__ */ new Map();
20110
20948
  const order = [];
20111
20949
  const bump = (raw, amount) => {
20112
20950
  if (typeof raw !== "string") return;
20113
- const trimmed = raw.trim();
20114
- if (!trimmed) return;
20115
- if (!counts.has(trimmed)) order.push(trimmed);
20116
- counts.set(trimmed, (counts.get(trimmed) ?? 0) + amount);
20951
+ const trimmed5 = raw.trim();
20952
+ if (!trimmed5) return;
20953
+ if (!counts.has(trimmed5)) order.push(trimmed5);
20954
+ counts.set(trimmed5, (counts.get(trimmed5) ?? 0) + amount);
20117
20955
  };
20118
20956
  bump(toolInput.file_path, 1);
20119
20957
  bump(toolInput.notebook_path, 1);
@@ -20153,7 +20991,7 @@ function editIntent({
20153
20991
  function recentAssistantContext(transcriptPath) {
20154
20992
  if (typeof transcriptPath !== "string" || !transcriptPath.trim()) return null;
20155
20993
  try {
20156
- const lines2 = readFileSync19(transcriptPath, "utf8").split("\n").slice(-200);
20994
+ const lines2 = readFileSync20(transcriptPath, "utf8").split("\n").slice(-200);
20157
20995
  for (let index = lines2.length - 1; index >= 0; index -= 1) {
20158
20996
  const line = lines2[index]?.trim();
20159
20997
  if (!line) continue;
@@ -20203,7 +21041,7 @@ function recordTouchedFromPayload({
20203
21041
  const toolInput = toolInputRaw && typeof toolInputRaw === "object" ? toolInputRaw : {};
20204
21042
  const toolName = typeof payload.tool_name === "string" && payload.tool_name.trim() ? payload.tool_name.trim() : "file edit";
20205
21043
  const cwd = typeof payload.cwd === "string" && payload.cwd.trim() ? payload.cwd.trim() : fallbackCwd;
20206
- const workingDirectory = path27.resolve(cwd);
21044
+ const workingDirectory = path29.resolve(cwd);
20207
21045
  const trimmedOverride = missionOverride?.trim();
20208
21046
  let missionId;
20209
21047
  let ambiguous = false;
@@ -20307,23 +21145,23 @@ var init_resource_observations = __esm({
20307
21145
 
20308
21146
  // src/runner-identity.ts
20309
21147
  import { randomUUID } from "node:crypto";
20310
- import { existsSync as existsSync24, mkdirSync as mkdirSync12, readFileSync as readFileSync20, writeFileSync as writeFileSync11 } from "node:fs";
21148
+ import { existsSync as existsSync25, mkdirSync as mkdirSync13, readFileSync as readFileSync21, writeFileSync as writeFileSync12 } from "node:fs";
20311
21149
  import { hostname as hostname4 } from "node:os";
20312
- import path28 from "node:path";
21150
+ import path30 from "node:path";
20313
21151
  function envValue(name) {
20314
21152
  const value = process.env[name]?.trim();
20315
21153
  return value && value.length > 0 ? value : null;
20316
21154
  }
20317
21155
  function runnerInstanceStatePath(dataDir = resolveGlobalDataDir()) {
20318
- return path28.join(dataDir, RUNNER_INSTANCE_STATE_FILENAME);
21156
+ return path30.join(dataDir, RUNNER_INSTANCE_STATE_FILENAME);
20319
21157
  }
20320
21158
  function resolveRunnerInstanceId(dataDir = resolveGlobalDataDir()) {
20321
21159
  const pinned = envValue("OVERLORD_RUNNER_INSTANCE_ID");
20322
21160
  if (pinned) return pinned;
20323
21161
  const statePath = runnerInstanceStatePath(dataDir);
20324
- if (existsSync24(statePath)) {
21162
+ if (existsSync25(statePath)) {
20325
21163
  try {
20326
- const parsed = JSON.parse(readFileSync20(statePath, "utf8"));
21164
+ const parsed = JSON.parse(readFileSync21(statePath, "utf8"));
20327
21165
  if (typeof parsed.runnerInstanceId === "string" && parsed.runnerInstanceId.trim()) {
20328
21166
  return parsed.runnerInstanceId.trim();
20329
21167
  }
@@ -20332,8 +21170,8 @@ function resolveRunnerInstanceId(dataDir = resolveGlobalDataDir()) {
20332
21170
  }
20333
21171
  const runnerInstanceId = randomUUID();
20334
21172
  try {
20335
- mkdirSync12(path28.dirname(statePath), { recursive: true });
20336
- writeFileSync11(statePath, `${JSON.stringify({ runnerInstanceId }, null, 2)}
21173
+ mkdirSync13(path30.dirname(statePath), { recursive: true });
21174
+ writeFileSync12(statePath, `${JSON.stringify({ runnerInstanceId }, null, 2)}
20337
21175
  `, { mode: 384 });
20338
21176
  } catch {
20339
21177
  }
@@ -20375,12 +21213,12 @@ var init_runner_identity = __esm({
20375
21213
 
20376
21214
  // src/runner-service.ts
20377
21215
  import { execFile } from "node:child_process";
20378
- import { chmodSync as chmodSync5, existsSync as existsSync25, mkdirSync as mkdirSync13, readFileSync as readFileSync21, rmSync as rmSync6, writeFileSync as writeFileSync12 } from "node:fs";
20379
- import os4 from "node:os";
20380
- import path29 from "node:path";
21216
+ import { chmodSync as chmodSync5, existsSync as existsSync26, mkdirSync as mkdirSync14, readFileSync as readFileSync22, rmSync as rmSync6, writeFileSync as writeFileSync13 } from "node:fs";
21217
+ import os5 from "node:os";
21218
+ import path31 from "node:path";
20381
21219
  import { promisify } from "node:util";
20382
21220
  function writeServiceFile(filePath, contents) {
20383
- writeFileSync12(filePath, contents, { mode: 384 });
21221
+ writeFileSync13(filePath, contents, { mode: 384 });
20384
21222
  chmodSync5(filePath, 384);
20385
21223
  }
20386
21224
  function emptyRunnerServiceState() {
@@ -20399,21 +21237,21 @@ function emptyRunnerServiceState() {
20399
21237
  };
20400
21238
  }
20401
21239
  function runnerServiceStatePath(dataDir = resolveGlobalDataDir()) {
20402
- return path29.join(dataDir, RUNNER_SERVICE_STATE_FILENAME);
21240
+ return path31.join(dataDir, RUNNER_SERVICE_STATE_FILENAME);
20403
21241
  }
20404
21242
  function readRunnerServiceState(dataDir = resolveGlobalDataDir()) {
20405
21243
  const filePath = runnerServiceStatePath(dataDir);
20406
- if (!existsSync25(filePath)) return emptyRunnerServiceState();
21244
+ if (!existsSync26(filePath)) return emptyRunnerServiceState();
20407
21245
  try {
20408
- const parsed = JSON.parse(readFileSync21(filePath, "utf8"));
21246
+ const parsed = JSON.parse(readFileSync22(filePath, "utf8"));
20409
21247
  return { ...emptyRunnerServiceState(), ...parsed };
20410
21248
  } catch {
20411
21249
  return emptyRunnerServiceState();
20412
21250
  }
20413
21251
  }
20414
21252
  function writeRunnerServiceState(state, dataDir = resolveGlobalDataDir()) {
20415
- mkdirSync13(dataDir, { recursive: true });
20416
- writeFileSync12(runnerServiceStatePath(dataDir), `${JSON.stringify(state, null, 2)}
21253
+ mkdirSync14(dataDir, { recursive: true });
21254
+ writeFileSync13(runnerServiceStatePath(dataDir), `${JSON.stringify(state, null, 2)}
20417
21255
  `, "utf8");
20418
21256
  }
20419
21257
  function patchRunnerServiceState(patch, dataDir = resolveGlobalDataDir()) {
@@ -20422,13 +21260,13 @@ function patchRunnerServiceState(patch, dataDir = resolveGlobalDataDir()) {
20422
21260
  return next;
20423
21261
  }
20424
21262
  function runnerFocusStatePath(dataDir = resolveGlobalDataDir()) {
20425
- return path29.join(dataDir, RUNNER_FOCUS_STATE_FILENAME);
21263
+ return path31.join(dataDir, RUNNER_FOCUS_STATE_FILENAME);
20426
21264
  }
20427
21265
  function readDesktopFocusState(dataDir = resolveGlobalDataDir()) {
20428
21266
  const filePath = runnerFocusStatePath(dataDir);
20429
- if (!existsSync25(filePath)) return { lastFocusedAt: null };
21267
+ if (!existsSync26(filePath)) return { lastFocusedAt: null };
20430
21268
  try {
20431
- const parsed = JSON.parse(readFileSync21(filePath, "utf8"));
21269
+ const parsed = JSON.parse(readFileSync22(filePath, "utf8"));
20432
21270
  return { lastFocusedAt: parsed.lastFocusedAt ?? null };
20433
21271
  } catch {
20434
21272
  return { lastFocusedAt: null };
@@ -20458,17 +21296,17 @@ function nextRunnerLastError(pollError) {
20458
21296
  }
20459
21297
  function resolveOverlordAppInvocation({
20460
21298
  platform: platform2 = process.platform,
20461
- homedir: homedir2 = os4.homedir(),
20462
- exists = existsSync25
21299
+ homedir: homedir2 = os5.homedir(),
21300
+ exists = existsSync26
20463
21301
  } = {}) {
20464
21302
  if (platform2 !== "darwin") return null;
20465
21303
  const appDirs = [
20466
21304
  "/Applications/Overlord.app",
20467
- path29.join(homedir2, "Applications", "Overlord.app")
21305
+ path31.join(homedir2, "Applications", "Overlord.app")
20468
21306
  ];
20469
21307
  for (const appDir of appDirs) {
20470
- const program = path29.join(appDir, "Contents", "MacOS", "Overlord");
20471
- const script = path29.join(appDir, "Contents", "Resources", "cli", "bin", "ovld.mjs");
21308
+ const program = path31.join(appDir, "Contents", "MacOS", "Overlord");
21309
+ const script = path31.join(appDir, "Contents", "Resources", "cli", "bin", "ovld.mjs");
20472
21310
  if (exists(program) && exists(script)) {
20473
21311
  return { program, args: [script, "runner", "supervise"], runAsElectronNode: true };
20474
21312
  }
@@ -20480,7 +21318,7 @@ function resolveOvldInvocation(argv = process.argv, execPath = process.execPath)
20480
21318
  if (override) {
20481
21319
  return { program: override, args: ["runner", "supervise"] };
20482
21320
  }
20483
- const scriptPath = argv[1] ? path29.resolve(argv[1]) : "";
21321
+ const scriptPath = argv[1] ? path31.resolve(argv[1]) : "";
20484
21322
  if (process.env.ELECTRON_RUN_AS_NODE) {
20485
21323
  return scriptPath ? { program: execPath, args: [scriptPath, "runner", "supervise"], runAsElectronNode: true } : { program: execPath, args: ["runner", "supervise"], runAsElectronNode: true };
20486
21324
  }
@@ -20513,7 +21351,7 @@ function buildRunnerServiceEnv({
20513
21351
  PATH: process.env.PATH?.trim() || "/usr/local/bin:/usr/bin:/bin"
20514
21352
  };
20515
21353
  const home = overlordHome?.trim() || process.env.OVLD_HOME?.trim();
20516
- if (home) env.OVLD_HOME = path29.resolve(home);
21354
+ if (home) env.OVLD_HOME = path31.resolve(home);
20517
21355
  const token = process.env.OVERLORD_USER_TOKEN?.trim() || process.env.OVLD_USER_TOKEN?.trim();
20518
21356
  if (token) env.OVERLORD_USER_TOKEN = token;
20519
21357
  if (runAsElectronNode || process.env.ELECTRON_RUN_AS_NODE) env.ELECTRON_RUN_AS_NODE = "1";
@@ -20552,9 +21390,9 @@ ${envEntries}
20552
21390
  <key>KeepAlive</key>
20553
21391
  <true/>
20554
21392
  <key>StandardOutPath</key>
20555
- <string>${xmlEscape(path29.join(logDir, "runner-service.out.log"))}</string>
21393
+ <string>${xmlEscape(path31.join(logDir, "runner-service.out.log"))}</string>
20556
21394
  <key>StandardErrorPath</key>
20557
- <string>${xmlEscape(path29.join(logDir, "runner-service.err.log"))}</string>
21395
+ <string>${xmlEscape(path31.join(logDir, "runner-service.err.log"))}</string>
20558
21396
  <key>ProcessType</key>
20559
21397
  <string>Background</string>
20560
21398
  </dict>
@@ -20585,12 +21423,12 @@ WantedBy=default.target
20585
21423
  `;
20586
21424
  }
20587
21425
  function launchAgentsDir() {
20588
- return path29.join(os4.homedir(), "Library", "LaunchAgents");
21426
+ return path31.join(os5.homedir(), "Library", "LaunchAgents");
20589
21427
  }
20590
21428
  function systemdUserDir() {
20591
21429
  const xdg = process.env.XDG_CONFIG_HOME?.trim();
20592
- const base = xdg ? path29.resolve(xdg) : path29.join(os4.homedir(), ".config");
20593
- return path29.join(base, "systemd", "user");
21430
+ const base = xdg ? path31.resolve(xdg) : path31.join(os5.homedir(), ".config");
21431
+ return path31.join(base, "systemd", "user");
20594
21432
  }
20595
21433
  async function runCommand(program, args) {
20596
21434
  const { stdout } = await execFileAsync(program, args);
@@ -20619,19 +21457,19 @@ var init_runner_service = __esm({
20619
21457
  kind = "launchd";
20620
21458
  identifier = LAUNCHD_LABEL;
20621
21459
  unitPath() {
20622
- return path29.join(launchAgentsDir(), `${LAUNCHD_LABEL}.plist`);
21460
+ return path31.join(launchAgentsDir(), `${LAUNCHD_LABEL}.plist`);
20623
21461
  }
20624
21462
  render(opts) {
20625
21463
  return renderLaunchdPlist({
20626
21464
  label: LAUNCHD_LABEL,
20627
21465
  invocation: opts.invocation,
20628
21466
  env: opts.env,
20629
- logDir: path29.join(resolveGlobalDataDir(), "logs")
21467
+ logDir: path31.join(resolveGlobalDataDir(), "logs")
20630
21468
  });
20631
21469
  }
20632
21470
  async install(opts) {
20633
- mkdirSync13(launchAgentsDir(), { recursive: true });
20634
- mkdirSync13(path29.join(resolveGlobalDataDir(), "logs"), { recursive: true });
21471
+ mkdirSync14(launchAgentsDir(), { recursive: true });
21472
+ mkdirSync14(path31.join(resolveGlobalDataDir(), "logs"), { recursive: true });
20635
21473
  writeServiceFile(this.unitPath(), this.render(opts));
20636
21474
  if (opts.autoStart) await this.start();
20637
21475
  }
@@ -20661,10 +21499,10 @@ var init_runner_service = __esm({
20661
21499
  await this.stop();
20662
21500
  } catch {
20663
21501
  }
20664
- if (existsSync25(this.unitPath())) rmSync6(this.unitPath());
21502
+ if (existsSync26(this.unitPath())) rmSync6(this.unitPath());
20665
21503
  }
20666
21504
  async status() {
20667
- const installed = existsSync25(this.unitPath());
21505
+ const installed = existsSync26(this.unitPath());
20668
21506
  try {
20669
21507
  const { stdout } = await runCommand("launchctl", ["list"]);
20670
21508
  const line = stdout.split("\n").find((row) => row.includes(LAUNCHD_LABEL));
@@ -20680,13 +21518,13 @@ var init_runner_service = __esm({
20680
21518
  kind = "systemd";
20681
21519
  identifier = `${SYSTEMD_UNIT_NAME}.service`;
20682
21520
  unitPath() {
20683
- return path29.join(systemdUserDir(), `${SYSTEMD_UNIT_NAME}.service`);
21521
+ return path31.join(systemdUserDir(), `${SYSTEMD_UNIT_NAME}.service`);
20684
21522
  }
20685
21523
  render(opts) {
20686
21524
  return renderSystemdUnit(opts);
20687
21525
  }
20688
21526
  async install(opts) {
20689
- mkdirSync13(systemdUserDir(), { recursive: true });
21527
+ mkdirSync14(systemdUserDir(), { recursive: true });
20690
21528
  writeServiceFile(this.unitPath(), this.render(opts));
20691
21529
  await runCommand("systemctl", ["--user", "daemon-reload"]);
20692
21530
  await runCommand("systemctl", ["--user", "enable", this.identifier]);
@@ -20707,14 +21545,14 @@ var init_runner_service = __esm({
20707
21545
  await runCommand("systemctl", ["--user", "disable", this.identifier]);
20708
21546
  } catch {
20709
21547
  }
20710
- if (existsSync25(this.unitPath())) rmSync6(this.unitPath());
21548
+ if (existsSync26(this.unitPath())) rmSync6(this.unitPath());
20711
21549
  try {
20712
21550
  await runCommand("systemctl", ["--user", "daemon-reload"]);
20713
21551
  } catch {
20714
21552
  }
20715
21553
  }
20716
21554
  async status() {
20717
- const installed = existsSync25(this.unitPath());
21555
+ const installed = existsSync26(this.unitPath());
20718
21556
  try {
20719
21557
  const { stdout } = await runCommand("systemctl", ["--user", "is-active", this.identifier]);
20720
21558
  return { installed, running: stdout.trim() === "active" ? "running" : "stopped" };
@@ -20729,9 +21567,9 @@ var init_runner_service = __esm({
20729
21567
  // src/select-prompt.ts
20730
21568
  import { createInterface as createInterface4 } from "node:readline";
20731
21569
  function parseNumberedSelection(answer, count) {
20732
- const trimmed = answer.trim();
20733
- if (!/^\d+$/.test(trimmed)) return null;
20734
- const value = Number.parseInt(trimmed, 10);
21570
+ const trimmed5 = answer.trim();
21571
+ if (!/^\d+$/.test(trimmed5)) return null;
21572
+ const value = Number.parseInt(trimmed5, 10);
20735
21573
  if (!Number.isInteger(value) || value < 1 || value > count) return null;
20736
21574
  return value - 1;
20737
21575
  }
@@ -20781,14 +21619,14 @@ var init_select_prompt = __esm({
20781
21619
 
20782
21620
  // src/session-key.ts
20783
21621
  import { createHash as createHash10 } from "node:crypto";
20784
- import { existsSync as existsSync26, mkdirSync as mkdirSync14, readFileSync as readFileSync22, rmSync as rmSync7, writeFileSync as writeFileSync13 } from "node:fs";
20785
- import path30 from "node:path";
21622
+ import { existsSync as existsSync27, mkdirSync as mkdirSync15, readFileSync as readFileSync23, rmSync as rmSync7, writeFileSync as writeFileSync14 } from "node:fs";
21623
+ import path32 from "node:path";
20786
21624
  function sessionKeyCachePath({
20787
21625
  missionId,
20788
21626
  workingDirectory
20789
21627
  }) {
20790
- const key = createHash10("sha256").update(`${path30.resolve(workingDirectory)}\0${missionId}`).digest("hex");
20791
- return path30.join(resolveGlobalDataDir(), "protocol-session-keys", key);
21628
+ const key = createHash10("sha256").update(`${path32.resolve(workingDirectory)}\0${missionId}`).digest("hex");
21629
+ return path32.join(resolveGlobalDataDir(), "protocol-session-keys", key);
20792
21630
  }
20793
21631
  function readCachedSessionKey({
20794
21632
  missionId,
@@ -20796,8 +21634,8 @@ function readCachedSessionKey({
20796
21634
  }) {
20797
21635
  try {
20798
21636
  const filePath = sessionKeyCachePath({ missionId, workingDirectory });
20799
- if (!existsSync26(filePath)) return void 0;
20800
- const raw = JSON.parse(readFileSync22(filePath, "utf8"));
21637
+ if (!existsSync27(filePath)) return void 0;
21638
+ const raw = JSON.parse(readFileSync23(filePath, "utf8"));
20801
21639
  return typeof raw.sessionKey === "string" && raw.sessionKey.trim() ? raw.sessionKey.trim() : void 0;
20802
21640
  } catch {
20803
21641
  return void 0;
@@ -20809,13 +21647,13 @@ function writeCachedSessionKey({
20809
21647
  sessionKey
20810
21648
  }) {
20811
21649
  try {
20812
- const trimmed = sessionKey.trim();
20813
- if (!trimmed) return;
21650
+ const trimmed5 = sessionKey.trim();
21651
+ if (!trimmed5) return;
20814
21652
  const filePath = sessionKeyCachePath({ missionId, workingDirectory });
20815
- mkdirSync14(path30.dirname(filePath), { recursive: true });
20816
- writeFileSync13(
21653
+ mkdirSync15(path32.dirname(filePath), { recursive: true });
21654
+ writeFileSync14(
20817
21655
  filePath,
20818
- JSON.stringify({ sessionKey: trimmed, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }),
21656
+ JSON.stringify({ sessionKey: trimmed5, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }),
20819
21657
  { mode: 384 }
20820
21658
  );
20821
21659
  } catch {
@@ -20827,7 +21665,7 @@ function clearCachedSessionKey({
20827
21665
  }) {
20828
21666
  try {
20829
21667
  const filePath = sessionKeyCachePath({ missionId, workingDirectory });
20830
- if (existsSync26(filePath)) rmSync7(filePath);
21668
+ if (existsSync27(filePath)) rmSync7(filePath);
20831
21669
  } catch {
20832
21670
  }
20833
21671
  }
@@ -20845,9 +21683,9 @@ __export(commands_exports, {
20845
21683
  runManagementCommand: () => runManagementCommand,
20846
21684
  runProtocolCommand: () => runProtocolCommand
20847
21685
  });
20848
- import { existsSync as existsSync27, readFileSync as readFileSync23 } from "node:fs";
20849
- import os5 from "node:os";
20850
- import path31 from "node:path";
21686
+ import { existsSync as existsSync28, readFileSync as readFileSync24 } from "node:fs";
21687
+ import os6 from "node:os";
21688
+ import path33 from "node:path";
20851
21689
  function resourceAccessModeBody(value) {
20852
21690
  if (typeof value !== "string") return {};
20853
21691
  const normalized = value.trim().toLowerCase();
@@ -20893,7 +21731,7 @@ function readChangedFilesFromFlags(flags, stdin) {
20893
21731
  if (typeof fileFlag === "string") {
20894
21732
  const raw = fileFlag === "-" ? stdin ?? "" : (() => {
20895
21733
  try {
20896
- return readFileSync23(fileFlag, "utf8");
21734
+ return readFileSync24(fileFlag, "utf8");
20897
21735
  } catch {
20898
21736
  return "";
20899
21737
  }
@@ -20945,7 +21783,7 @@ function readJsonFlagContent({
20945
21783
  if (typeof filePath === "string") {
20946
21784
  if (fileInputs[fileFlag] !== void 0) return fileInputs[fileFlag];
20947
21785
  try {
20948
- return readFileSync23(filePath, "utf8");
21786
+ return readFileSync24(filePath, "utf8");
20949
21787
  } catch {
20950
21788
  return void 0;
20951
21789
  }
@@ -21249,7 +22087,7 @@ async function resolveProtocolFileInputs({
21249
22087
  } else if (process.stdin.isTTY) {
21250
22088
  stdinContent = "";
21251
22089
  } else {
21252
- stdinContent = readFileSync23(0, "utf8");
22090
+ stdinContent = readFileSync24(0, "utf8");
21253
22091
  }
21254
22092
  return stdinContent;
21255
22093
  };
@@ -21263,7 +22101,7 @@ async function resolveProtocolFileInputs({
21263
22101
  fileInputs[flagName] = content;
21264
22102
  stdinPayload = content;
21265
22103
  } else {
21266
- fileInputs[flagName] = readFileSync23(filePath, "utf8");
22104
+ fileInputs[flagName] = readFileSync24(filePath, "utf8");
21267
22105
  }
21268
22106
  }
21269
22107
  if (stdinPayload === void 0 && stdin !== void 0 && Object.keys(fileInputs).length === 0) {
@@ -21328,7 +22166,7 @@ async function runProtocolCommand({
21328
22166
  });
21329
22167
  if (subcommand === "record-touched") {
21330
22168
  const missionOverride = flagValue(parsed.flags, "--mission-id") ?? process.env.MISSION_ID ?? process.env.OVERLORD_MISSION_ID;
21331
- const rawPayload = stdin ?? (process.stdin.isTTY ? "" : readFileSync23(0, "utf8"));
22169
+ const rawPayload = stdin ?? (process.stdin.isTTY ? "" : readFileSync24(0, "utf8"));
21332
22170
  const result2 = recordTouchedFromPayload({
21333
22171
  rawPayload,
21334
22172
  missionOverride,
@@ -21459,9 +22297,9 @@ async function runProtocolCommand({
21459
22297
  clearCachedSessionKey({ missionId, workingDirectory });
21460
22298
  removeActiveSession({ workingDirectory, missionId });
21461
22299
  clearActiveMissionPointer(workingDirectory);
21462
- const connectorInstallsEditHook = existsSync27(path31.join(os5.homedir(), ".claude")) || existsSync27(
21463
- path31.join(
21464
- os5.homedir(),
22300
+ const connectorInstallsEditHook = existsSync28(path33.join(os6.homedir(), ".claude")) || existsSync28(
22301
+ path33.join(
22302
+ os6.homedir(),
21465
22303
  ".cursor",
21466
22304
  "plugins",
21467
22305
  "local",
@@ -21560,7 +22398,7 @@ async function runManagementCommand({
21560
22398
  case "add-cwd": {
21561
22399
  const directory = flagValue(parsed.flags, "--directory") ?? process.cwd();
21562
22400
  const existingProjectJson = readProjectJsonLink(
21563
- path31.join(directory, ".overlord", "project.json")
22401
+ path33.join(directory, ".overlord", "project.json")
21564
22402
  );
21565
22403
  const resourceKey = flagValue(parsed.flags, "--key") ?? existingProjectJson?.resourceKey;
21566
22404
  let projectId = flagValue(parsed.flags, "--project-id");
@@ -21951,13 +22789,13 @@ async function runManagementCommand({
21951
22789
  rationales: `/api/missions/${encodeURIComponent(missionId)}/file-changes`,
21952
22790
  deliveries: `/api/missions/${encodeURIComponent(missionId)}/deliveries`
21953
22791
  };
21954
- const path32 = sub ? pathBySub[sub] : void 0;
21955
- if (!path32) {
22792
+ const path34 = sub ? pathBySub[sub] : void 0;
22793
+ if (!path34) {
21956
22794
  throw new CliError({
21957
22795
  message: "Usage: ovld mission context|events|deliveries|artifacts|rationales <missionId> [--json]"
21958
22796
  });
21959
22797
  }
21960
- const result = await runtime.backend.get(path32);
22798
+ const result = await runtime.backend.get(path34);
21961
22799
  if (json || sub === "context") printJson(result);
21962
22800
  else if (Array.isArray(result)) for (const row of result) console.log(JSON.stringify(row));
21963
22801
  else printJson(result);
@@ -22127,16 +22965,33 @@ The runner will not register a target for you \u2014 declare this machine first,
22127
22965
  sessionChannelId: typeof sessionChannel.channelId === "string" ? sessionChannel.channelId : void 0,
22128
22966
  sessionChannelToken: typeof sessionChannel.token === "string" ? sessionChannel.token : void 0,
22129
22967
  sessionChannelLaunchKind: typeof sessionChannel.launchKind === "string" ? sessionChannel.launchKind : void 0,
22968
+ launchSession: launchSessionSnapshotFromMetadata(asRecord5(requestRecord.metadata)),
22130
22969
  ...terminal,
22131
22970
  dryRun
22132
22971
  }
22133
22972
  });
22973
+ if (result.providerFallbackWarning) {
22974
+ console.error(`[overlord] ${result.providerFallbackWarning}`);
22975
+ }
22976
+ if (result.viewerOpen && result.viewerOpen.ok === false) {
22977
+ console.error(`[overlord] ${result.viewerOpen.warning}`);
22978
+ }
22134
22979
  if (result.status && result.status !== 0) {
22135
22980
  throw new CliError({ message: `Launch command exited with status ${result.status}` });
22136
22981
  }
22137
- await runtime.backend.post({ path: `/api/runner/requests/${requestId}/launched` });
22982
+ await runtime.backend.post({
22983
+ path: `/api/runner/requests/${requestId}/launched`,
22984
+ body: result.providerSession ? { providerSession: result.providerSession } : {}
22985
+ });
22138
22986
  if (json || dryRun) {
22139
- printJson({ request, plan: result.plan, status: result.status });
22987
+ printJson({
22988
+ request,
22989
+ plan: result.plan,
22990
+ status: result.status,
22991
+ providerSession: result.providerSession ?? null,
22992
+ viewerOpen: result.viewerOpen ?? null,
22993
+ providerFallbackWarning: result.providerFallbackWarning ?? null
22994
+ });
22140
22995
  } else {
22141
22996
  console.log(`Launched ${requestedAgent} for ${requestRecord.missionId}`);
22142
22997
  }
@@ -22318,6 +23173,7 @@ var init_commands = __esm({
22318
23173
  init_dist2();
22319
23174
  init_project_metadata();
22320
23175
  init_local_target_mutation_runner();
23176
+ init_terminal_profile_types2();
22321
23177
  init_active_mission();
22322
23178
  init_args();
22323
23179
  init_branch_preparation();