overlord-cli 0.2608120914.0 → 0.2608121927.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,559 @@ 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 resolveLatchExecutableOnPath(executable) {
16954
+ try {
16955
+ const found = execFileSync3("which", [executable], {
16956
+ encoding: "utf8",
16957
+ stdio: ["ignore", "pipe", "ignore"]
16958
+ }).trim();
16959
+ return found || null;
16960
+ } catch {
16961
+ return null;
16962
+ }
16963
+ }
16964
+ function resolveLatchExecutablePathFromEnvironment({ executable, homeDirectory = os3.homedir(), platform: platform2 = process.platform, resolveOnPath = resolveLatchExecutableOnPath, fileExists = existsSync16 }) {
16965
+ const name = trimmed2(executable) ?? DEFAULT_LATCH_EXECUTABLE;
16966
+ if (path17.isAbsolute(name) || name.includes("/") || name.includes("\\")) {
16967
+ return fileExists(name) ? path17.resolve(name) : null;
16968
+ }
16969
+ const resolvedOnPath = resolveOnPath(name);
16970
+ if (resolvedOnPath)
16971
+ return resolvedOnPath;
16972
+ const fallbacks = [
16973
+ path17.join(homeDirectory, ".local", "bin", name),
16974
+ ...platform2 === "darwin" ? [`/opt/homebrew/bin/${name}`, `/usr/local/bin/${name}`] : []
16975
+ ];
16976
+ const fallback = fallbacks.find(fileExists);
16977
+ return fallback ? path17.resolve(fallback) : null;
16978
+ }
16979
+ function resolveLatchExecutablePath(executable) {
16980
+ return resolveLatchExecutablePathFromEnvironment({ executable });
16981
+ }
16982
+ function notInstalledResult({ executable, checkedAt }) {
16983
+ return {
16984
+ state: "not_installed",
16985
+ executable,
16986
+ installCommand: LATCH_STANDALONE_INSTALL_COMMAND,
16987
+ checkedAt,
16988
+ latchSelectable: false,
16989
+ directSelectable: true
16990
+ };
16991
+ }
16992
+ function probeLatchCapabilities({ executable = DEFAULT_LATCH_EXECUTABLE, resolvePath = resolveLatchExecutablePath, runCommand: runCommand2 = defaultCommandRunner, now = () => (/* @__PURE__ */ new Date()).toISOString() } = {}) {
16993
+ const exe = trimmed2(executable) ?? DEFAULT_LATCH_EXECUTABLE;
16994
+ const checkedAt = now();
16995
+ const resolvedPath = resolvePath(exe);
16996
+ if (!resolvedPath) {
16997
+ return notInstalledResult({ executable: exe, checkedAt });
16998
+ }
16999
+ const ran = runCommand2({ executable: resolvedPath, argv: ["capabilities", "--json"] });
17000
+ if (ran.status === null && ran.stderr === "ENOENT") {
17001
+ return notInstalledResult({ executable: exe, checkedAt });
17002
+ }
17003
+ const report = parseLatchCapabilitiesReport(ran.stdout);
17004
+ if (!report) {
17005
+ return {
17006
+ state: "incompatible",
17007
+ executable: exe,
17008
+ resolvedPath,
17009
+ protocolVersion: null,
17010
+ productVersion: null,
17011
+ missingCapability: "capabilities",
17012
+ detail: ran.status === 0 ? "Latch capabilities output was not valid JSON in the expected shape." : `Latch capabilities failed (exit ${ran.status ?? "null"}).`,
17013
+ checkedAt,
17014
+ latchSelectable: false,
17015
+ directSelectable: true
17016
+ };
17017
+ }
17018
+ return evaluateLatchCapabilities({ report, executable: exe, resolvedPath, checkedAt });
17019
+ }
17020
+ function latchDiscoveryCacheKey({ executionTargetId, executable }) {
17021
+ const exe = trimmed2(executable) ?? DEFAULT_LATCH_EXECUTABLE;
17022
+ return `${executionTargetId}::${exe}`;
17023
+ }
17024
+ function readBinaryMtimeMs(resolvedPath) {
17025
+ if (!resolvedPath)
17026
+ return null;
17027
+ try {
17028
+ return statSync4(resolvedPath).mtimeMs;
17029
+ } catch {
17030
+ return null;
17031
+ }
17032
+ }
17033
+ function isLatchDiscoveryCacheFresh({ entry, resolvePath = resolveLatchExecutablePath }) {
17034
+ const { result } = entry;
17035
+ if (result.state === "not_installed") {
17036
+ return resolvePath(result.executable) === null;
17037
+ }
17038
+ const pathStill = result.resolvedPath;
17039
+ if (!pathStill || !existsSync16(pathStill))
17040
+ return false;
17041
+ const mtime = readBinaryMtimeMs(pathStill);
17042
+ if (mtime === null || entry.binaryMtimeMs === null)
17043
+ return false;
17044
+ return mtime === entry.binaryMtimeMs;
17045
+ }
17046
+ function readLatchDiscoveryCacheFile(filePath) {
17047
+ if (!existsSync16(filePath))
17048
+ return { version: 1, entries: {} };
17049
+ try {
17050
+ const parsed = JSON.parse(readFileSync15(filePath, "utf8"));
17051
+ if (parsed.version !== 1 || !parsed.entries || typeof parsed.entries !== "object") {
17052
+ return { version: 1, entries: {} };
17053
+ }
17054
+ return { version: 1, entries: parsed.entries };
17055
+ } catch {
17056
+ return { version: 1, entries: {} };
17057
+ }
17058
+ }
17059
+ function writeLatchDiscoveryCacheFile({ filePath, cache }) {
17060
+ mkdirSync9(path17.dirname(filePath), { recursive: true });
17061
+ writeFileSync8(filePath, `${JSON.stringify(cache, null, 2)}
17062
+ `, { mode: 384 });
17063
+ }
17064
+ function discoverLatchForExecutionTarget({ executionTargetId, executable = DEFAULT_LATCH_EXECUTABLE, cacheFilePath, force = false, resolvePath = resolveLatchExecutablePath, runCommand: runCommand2 = defaultCommandRunner, now = () => (/* @__PURE__ */ new Date()).toISOString() }) {
17065
+ const exe = trimmed2(executable) ?? DEFAULT_LATCH_EXECUTABLE;
17066
+ const key = latchDiscoveryCacheKey({ executionTargetId, executable: exe });
17067
+ const cache = readLatchDiscoveryCacheFile(cacheFilePath);
17068
+ const existing = cache.entries[key];
17069
+ if (!force && existing && isLatchDiscoveryCacheFresh({ entry: existing, resolvePath })) {
17070
+ return { ...existing.result, checkedAt: existing.result.checkedAt, directSelectable: true };
17071
+ }
17072
+ const result = probeLatchCapabilities({ executable: exe, resolvePath, runCommand: runCommand2, now });
17073
+ const binaryMtimeMs = result.state === "not_installed" ? null : readBinaryMtimeMs(result.resolvedPath);
17074
+ cache.entries[key] = {
17075
+ result,
17076
+ binaryMtimeMs,
17077
+ cachedAt: result.checkedAt
17078
+ };
17079
+ writeLatchDiscoveryCacheFile({ filePath: cacheFilePath, cache });
17080
+ return result;
17081
+ }
17082
+ var SUPPORTED_LATCH_PROTOCOL_VERSION, REQUIRED_LATCH_CAPABILITIES, LATCH_STANDALONE_INSTALL_COMMAND, LATCH_DISCOVERY_CACHE_FILENAME, defaultCommandRunner;
17083
+ var init_latch_discovery = __esm({
17084
+ "../packages/core/dist/service/latch-discovery.js"() {
17085
+ "use strict";
17086
+ init_terminal_profile_types2();
17087
+ SUPPORTED_LATCH_PROTOCOL_VERSION = 1;
17088
+ REQUIRED_LATCH_CAPABILITIES = ["create"];
17089
+ LATCH_STANDALONE_INSTALL_COMMAND = "curl -fsSL https://raw.githubusercontent.com/jchaselubitz/Latch/main/scripts/install-cli.sh | bash";
17090
+ LATCH_DISCOVERY_CACHE_FILENAME = "latch-discovery.json";
17091
+ defaultCommandRunner = ({ executable, argv }) => {
17092
+ try {
17093
+ const stdout = execFileSync3(executable, argv, {
17094
+ encoding: "utf8",
17095
+ stdio: ["ignore", "pipe", "pipe"],
17096
+ timeout: 5e3
17097
+ });
17098
+ return { status: 0, stdout: String(stdout), stderr: "" };
17099
+ } catch (error) {
17100
+ const err = error;
17101
+ if (err.code === "ENOENT") {
17102
+ return { status: null, stdout: "", stderr: "ENOENT" };
17103
+ }
17104
+ return {
17105
+ status: typeof err.status === "number" ? err.status : 1,
17106
+ stdout: err.stdout ? String(err.stdout) : "",
17107
+ stderr: err.stderr ? String(err.stderr) : String(error)
17108
+ };
17109
+ }
17110
+ };
17111
+ }
17112
+ });
17113
+
17114
+ // ../packages/core/dist/service/latch-launch.js
17115
+ function trimmed3(value) {
17116
+ return typeof value === "string" && value.trim() ? value.trim() : null;
17117
+ }
17118
+ function buildLatchCreateManifest({ commandString, shell = process.env.SHELL?.trim() || "/bin/bash", cwd, env, size = DEFAULT_LATCH_TERMINAL_SIZE, title, name, commandLabel, externalRunId }) {
17119
+ const shellPath = trimmed3(shell) ?? "/bin/bash";
17120
+ const cleanedEnv = {};
17121
+ for (const [key, value] of Object.entries(env)) {
17122
+ if (key.trim() && typeof value === "string")
17123
+ cleanedEnv[key] = value;
17124
+ }
17125
+ const display = {
17126
+ source: {
17127
+ kind: "overlord",
17128
+ ...trimmed3(externalRunId) ? { external_run_id: trimmed3(externalRunId) } : {}
17129
+ }
17130
+ };
17131
+ if (trimmed3(title))
17132
+ display.title = trimmed3(title);
17133
+ if (trimmed3(name))
17134
+ display.name = trimmed3(name);
17135
+ if (trimmed3(commandLabel))
17136
+ display.command_label = trimmed3(commandLabel);
17137
+ return {
17138
+ format_version: LATCH_MANIFEST_FORMAT_VERSION,
17139
+ launch: {
17140
+ argv: [shellPath, "-lc", commandString],
17141
+ cwd,
17142
+ env: cleanedEnv,
17143
+ inherit_env: true,
17144
+ size: {
17145
+ cols: Math.max(1, Math.floor(size.cols) || DEFAULT_LATCH_TERMINAL_SIZE.cols),
17146
+ rows: Math.max(1, Math.floor(size.rows) || DEFAULT_LATCH_TERMINAL_SIZE.rows)
17147
+ }
17148
+ },
17149
+ display
17150
+ };
17151
+ }
17152
+ function parseLatchCreateReport(raw) {
17153
+ try {
17154
+ const parsed = JSON.parse(raw);
17155
+ const id = trimmed3(parsed.session?.id);
17156
+ if (!id)
17157
+ return null;
17158
+ const protocolVersion = typeof parsed.protocolVersion === "number" && Number.isFinite(parsed.protocolVersion) ? parsed.protocolVersion : LATCH_MANIFEST_FORMAT_VERSION;
17159
+ return {
17160
+ protocolVersion,
17161
+ session: {
17162
+ id,
17163
+ name: trimmed3(parsed.session?.name) ?? id,
17164
+ state: trimmed3(parsed.session?.state) ?? "running",
17165
+ createdAt: trimmed3(parsed.session?.createdAt) ?? (/* @__PURE__ */ new Date()).toISOString()
17166
+ }
17167
+ };
17168
+ } catch {
17169
+ return null;
17170
+ }
17171
+ }
17172
+ function toExecutionProviderSession({ createReport, executionTargetId, createdAt }) {
17173
+ return {
17174
+ provider: "latch",
17175
+ providerSessionId: createReport.session.id,
17176
+ sessionName: createReport.session.name,
17177
+ executionTargetId: trimmed3(executionTargetId),
17178
+ agentSessionId: null,
17179
+ createdAt: createdAt ?? createReport.session.createdAt,
17180
+ lastObservedState: createReport.session.state
17181
+ };
17182
+ }
17183
+ function existingLatchProviderSession({ latchSessionId, executionTargetId, createdAt = (/* @__PURE__ */ new Date()).toISOString() }) {
17184
+ const providerSessionId = trimmed3(latchSessionId);
17185
+ if (!providerSessionId)
17186
+ return null;
17187
+ return {
17188
+ provider: "latch",
17189
+ providerSessionId,
17190
+ sessionName: null,
17191
+ executionTargetId: trimmed3(executionTargetId),
17192
+ agentSessionId: null,
17193
+ createdAt,
17194
+ lastObservedState: "running"
17195
+ };
17196
+ }
17197
+ function latchViewerFlagForKind(kind) {
17198
+ switch (trimmed3(kind)?.toLowerCase()) {
17199
+ case "iterm":
17200
+ case "iterm2":
17201
+ return "iterm";
17202
+ default:
17203
+ return null;
17204
+ }
17205
+ }
17206
+ function latchAttachCommand({ executable = "latch", providerSessionId }) {
17207
+ return `${trimmed3(executable) ?? "latch"} attach ${providerSessionId}`;
17208
+ }
17209
+ function shouldUseLatchProvider({ providerKind, latchSelectable }) {
17210
+ return trimmed3(providerKind)?.toLowerCase() === "latch" && latchSelectable === true;
17211
+ }
17212
+ var LATCH_MANIFEST_FORMAT_VERSION, DEFAULT_LATCH_TERMINAL_SIZE;
17213
+ var init_latch_launch = __esm({
17214
+ "../packages/core/dist/service/latch-launch.js"() {
17215
+ "use strict";
17216
+ LATCH_MANIFEST_FORMAT_VERSION = 1;
17217
+ DEFAULT_LATCH_TERMINAL_SIZE = { cols: 120, rows: 36 };
17218
+ }
17219
+ });
17220
+
17221
+ // ../packages/core/dist/service/latch-session.js
17222
+ import { spawnSync as spawnSync2 } from "node:child_process";
17223
+ function trimmed4(value) {
17224
+ return typeof value === "string" && value.trim() ? value.trim() : null;
17225
+ }
17226
+ function parseState(value) {
17227
+ switch (trimmed4(value)) {
17228
+ case "running":
17229
+ return "running";
17230
+ case "exited":
17231
+ return "exited";
17232
+ case "stopping":
17233
+ return "stopping";
17234
+ case "lost":
17235
+ return "lost";
17236
+ default:
17237
+ return null;
17238
+ }
17239
+ }
17240
+ function runLatchJson({ executable, args }) {
17241
+ const result = spawnSync2(executable, args, {
17242
+ encoding: "utf8",
17243
+ shell: false,
17244
+ timeout: 1e4,
17245
+ maxBuffer: 1024 * 1024
17246
+ });
17247
+ if (result.error) {
17248
+ throw new LatchSessionCommandError(result.error.message);
17249
+ }
17250
+ if (result.status !== 0) {
17251
+ const detail = (result.stderr || result.stdout || `exit ${result.status ?? "unknown"}`).trim().slice(0, 500);
17252
+ throw new LatchSessionCommandError(detail || "Latch command failed.");
17253
+ }
17254
+ try {
17255
+ const parsed = JSON.parse(result.stdout);
17256
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
17257
+ throw new Error("not an object");
17258
+ }
17259
+ return parsed;
17260
+ } catch {
17261
+ throw new LatchSessionCommandError("Latch returned an invalid JSON response.");
17262
+ }
17263
+ }
17264
+ function inspectLatchSession({ executable = "latch", providerSessionId }) {
17265
+ const sessionId = trimmed4(providerSessionId);
17266
+ if (!sessionId)
17267
+ throw new LatchSessionCommandError("A Latch session id is required.");
17268
+ const report = runLatchJson({
17269
+ executable: trimmed4(executable) ?? "latch",
17270
+ args: ["inspect", sessionId, "--json"]
17271
+ });
17272
+ const state = parseState(report.state);
17273
+ if (!state)
17274
+ throw new LatchSessionCommandError("Latch returned an unsupported session state.");
17275
+ const exit = report.exit && typeof report.exit === "object" && !Array.isArray(report.exit) ? report.exit : null;
17276
+ return {
17277
+ providerSessionId: trimmed4(report.id) ?? sessionId,
17278
+ name: trimmed4(report.name) ?? sessionId,
17279
+ state,
17280
+ exitCode: typeof exit?.code === "number" && Number.isFinite(exit.code) ? exit.code : null,
17281
+ inspectedAt: (/* @__PURE__ */ new Date()).toISOString()
17282
+ };
17283
+ }
17284
+ function openLatchSession({ executable = "latch", providerSessionId, viewerKind }) {
17285
+ const sessionId = trimmed4(providerSessionId);
17286
+ if (!sessionId)
17287
+ throw new LatchSessionCommandError("A Latch session id is required.");
17288
+ const viewer = latchViewerFlagForKind(viewerKind);
17289
+ if (!viewer) {
17290
+ throw new LatchSessionCommandError(`Latch cannot open the configured viewer "${viewerKind}".`);
17291
+ }
17292
+ const report = runLatchJson({
17293
+ executable: trimmed4(executable) ?? "latch",
17294
+ args: ["open", sessionId, "--with", viewer, "--json"]
17295
+ });
17296
+ if (report.opened !== true) {
17297
+ throw new LatchSessionCommandError(`Latch did not open the ${viewer} viewer.`);
17298
+ }
17299
+ return {
17300
+ providerSessionId: trimmed4(report.id) ?? sessionId,
17301
+ viewer: trimmed4(report.viewer) ?? viewer,
17302
+ opened: true
17303
+ };
17304
+ }
17305
+ function stopLatchSession({ executable = "latch", providerSessionId }) {
17306
+ const sessionId = trimmed4(providerSessionId);
17307
+ if (!sessionId)
17308
+ throw new LatchSessionCommandError("A Latch session id is required.");
17309
+ const report = runLatchJson({
17310
+ executable: trimmed4(executable) ?? "latch",
17311
+ args: ["stop", sessionId, "--json"]
17312
+ });
17313
+ const state = parseState(report.state);
17314
+ if (!state)
17315
+ throw new LatchSessionCommandError("Latch returned an unsupported session state.");
17316
+ return {
17317
+ providerSessionId: trimmed4(report.id) ?? sessionId,
17318
+ state
17319
+ };
17320
+ }
17321
+ var LatchSessionCommandError;
17322
+ var init_latch_session = __esm({
17323
+ "../packages/core/dist/service/latch-session.js"() {
17324
+ "use strict";
17325
+ init_latch_launch();
17326
+ LatchSessionCommandError = class extends Error {
17327
+ constructor(message) {
17328
+ super(message);
17329
+ this.name = "LatchSessionCommandError";
17330
+ }
17331
+ };
17332
+ }
17333
+ });
17334
+
17335
+ // ../packages/core/dist/service/local-target/git-run.js
17336
+ import { execFileSync as execFileSync4 } from "node:child_process";
16789
17337
  function runGit2(cwd, args) {
16790
17338
  try {
16791
- return execFileSync3("git", args, {
17339
+ return execFileSync4("git", args, {
16792
17340
  cwd,
16793
17341
  encoding: "utf8",
16794
17342
  stdio: ["ignore", "pipe", "ignore"],
@@ -16800,7 +17348,7 @@ function runGit2(cwd, args) {
16800
17348
  }
16801
17349
  function runGitResult(cwd, args) {
16802
17350
  try {
16803
- const stdout = execFileSync3("git", args, {
17351
+ const stdout = execFileSync4("git", args, {
16804
17352
  cwd,
16805
17353
  encoding: "utf8",
16806
17354
  stdio: ["ignore", "pipe", "pipe"],
@@ -16823,13 +17371,13 @@ var init_git_run = __esm({
16823
17371
  });
16824
17372
 
16825
17373
  // ../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";
17374
+ import { existsSync as existsSync17, realpathSync as realpathSync2 } from "node:fs";
17375
+ import path18 from "node:path";
16828
17376
  function resolveRealPath(targetPath) {
16829
17377
  try {
16830
17378
  return realpathSync2.native(targetPath);
16831
17379
  } catch {
16832
- return path17.resolve(targetPath);
17380
+ return path18.resolve(targetPath);
16833
17381
  }
16834
17382
  }
16835
17383
  function worktreeIsDirty(worktreePath) {
@@ -16859,7 +17407,7 @@ function removeGitWorktree({ primaryRepoPath, worktreePath, force }) {
16859
17407
  args.push(worktreePath);
16860
17408
  runGitResult(primaryRepoPath, args);
16861
17409
  runGitResult(primaryRepoPath, ["worktree", "prune"]);
16862
- return !existsSync16(worktreePath);
17410
+ return !existsSync17(worktreePath);
16863
17411
  }
16864
17412
  function collectManagedWorktrees({ worktreeRoot, projects }) {
16865
17413
  const resolvedRoot = resolveRealPath(worktreeRoot);
@@ -16867,7 +17415,7 @@ function collectManagedWorktrees({ worktreeRoot, projects }) {
16867
17415
  const seen = /* @__PURE__ */ new Set();
16868
17416
  for (const project of projects) {
16869
17417
  const repoPath = project.primaryRepoPath;
16870
- if (!repoPath || !existsSync16(repoPath))
17418
+ if (!repoPath || !existsSync17(repoPath))
16871
17419
  continue;
16872
17420
  const out = runGitResult(repoPath, ["worktree", "list", "--porcelain"]);
16873
17421
  if (!out.ok)
@@ -16878,7 +17426,7 @@ function collectManagedWorktrees({ worktreeRoot, projects }) {
16878
17426
  if (!currentPath)
16879
17427
  return;
16880
17428
  const resolved = resolveRealPath(currentPath);
16881
- const underRoot = resolved === resolvedRoot || resolved.startsWith(resolvedRoot + path17.sep);
17429
+ const underRoot = resolved === resolvedRoot || resolved.startsWith(resolvedRoot + path18.sep);
16882
17430
  if (underRoot && !seen.has(resolved)) {
16883
17431
  seen.add(resolved);
16884
17432
  entries.push({
@@ -16906,7 +17454,7 @@ function collectManagedWorktrees({ worktreeRoot, projects }) {
16906
17454
  return entries;
16907
17455
  }
16908
17456
  function removeManagedWorktree({ path: worktreePath, primaryRepoPath, force }) {
16909
- const target = path17.resolve(worktreePath);
17457
+ const target = path18.resolve(worktreePath);
16910
17458
  if (!force && worktreeIsDirty(target)) {
16911
17459
  return {
16912
17460
  removed: [],
@@ -16920,7 +17468,7 @@ function purgeManagedWorktrees({ entries }) {
16920
17468
  const removed = [];
16921
17469
  const skipped = [];
16922
17470
  for (const entry of entries) {
16923
- const target = path17.resolve(entry.path);
17471
+ const target = path18.resolve(entry.path);
16924
17472
  if (worktreeIsDirty(target)) {
16925
17473
  skipped.push({ path: target, reason: "uncommitted changes" });
16926
17474
  continue;
@@ -16945,10 +17493,10 @@ var init_worktree_git = __esm({
16945
17493
  });
16946
17494
 
16947
17495
  // ../packages/core/dist/service/local-target/branch-actions-git.js
16948
- import { existsSync as existsSync17 } from "node:fs";
17496
+ import { existsSync as existsSync18 } from "node:fs";
16949
17497
  function integrateBranch(input) {
16950
17498
  const { branchName, baseBranch, worktreePath, primaryRepoPath } = input;
16951
- if (!existsSync17(worktreePath)) {
17499
+ if (!existsSync18(worktreePath)) {
16952
17500
  return {
16953
17501
  ok: false,
16954
17502
  code: "BRANCH_NO_WORKTREE",
@@ -17022,15 +17570,15 @@ function integrateBranch(input) {
17022
17570
  }
17023
17571
  function commitBranch(input) {
17024
17572
  const { branchName, worktreePath } = input;
17025
- const trimmed = (input.message ?? "").trim();
17026
- if (!trimmed) {
17573
+ const trimmed5 = (input.message ?? "").trim();
17574
+ if (!trimmed5) {
17027
17575
  return {
17028
17576
  ok: false,
17029
17577
  code: "BRANCH_COMMIT_MESSAGE_REQUIRED",
17030
17578
  message: "A commit message is required."
17031
17579
  };
17032
17580
  }
17033
- if (!existsSync17(worktreePath)) {
17581
+ if (!existsSync18(worktreePath)) {
17034
17582
  return {
17035
17583
  ok: false,
17036
17584
  code: "BRANCH_NO_WORKTREE",
@@ -17062,7 +17610,7 @@ function commitBranch(input) {
17062
17610
  detail: staged.stderr || staged.stdout
17063
17611
  };
17064
17612
  }
17065
- const commit = runGitResult(worktreePath, ["commit", "-m", trimmed]);
17613
+ const commit = runGitResult(worktreePath, ["commit", "-m", trimmed5]);
17066
17614
  if (!commit.ok) {
17067
17615
  return {
17068
17616
  ok: false,
@@ -17086,7 +17634,7 @@ function pushParent(input) {
17086
17634
  };
17087
17635
  }
17088
17636
  let summary = `Pushed ${baseBranch} to origin.`;
17089
- if (existsSync17(worktreePath) && !worktreeIsDirty(worktreePath)) {
17637
+ if (existsSync18(worktreePath) && !worktreeIsDirty(worktreePath)) {
17090
17638
  if (removeGitWorktree({ primaryRepoPath, worktreePath, force: false })) {
17091
17639
  summary += ` Removed the merged worktree for ${branchName}.`;
17092
17640
  }
@@ -17095,7 +17643,7 @@ function pushParent(input) {
17095
17643
  }
17096
17644
  function publishBranch(input) {
17097
17645
  const { branchName, worktreePath, primaryRepoPath } = input;
17098
- const repo = existsSync17(worktreePath) ? worktreePath : primaryRepoPath;
17646
+ const repo = existsSync18(worktreePath) ? worktreePath : primaryRepoPath;
17099
17647
  const push = runGitResult(repo, ["push", "-u", "origin", branchName]);
17100
17648
  if (!push.ok) {
17101
17649
  return {
@@ -17145,7 +17693,7 @@ var init_branch_status_git = __esm({
17145
17693
  });
17146
17694
 
17147
17695
  // ../packages/core/dist/service/local-target/commit-message-diff-git.js
17148
- import { existsSync as existsSync18 } from "node:fs";
17696
+ import { existsSync as existsSync19 } from "node:fs";
17149
17697
  function collectWorktreeChanges(worktreePath) {
17150
17698
  const status = runGitResult(worktreePath, ["status", "--porcelain"]);
17151
17699
  const diff = runGitResult(worktreePath, ["diff", "HEAD"]);
@@ -17161,7 +17709,7 @@ ${diff.stdout}`);
17161
17709
  return sections.join("\n\n");
17162
17710
  }
17163
17711
  function gatherCommitMessageDiff(worktreePath) {
17164
- if (!existsSync18(worktreePath)) {
17712
+ if (!existsSync19(worktreePath)) {
17165
17713
  return {
17166
17714
  ok: false,
17167
17715
  code: "BRANCH_NO_WORKTREE",
@@ -17187,10 +17735,10 @@ var init_commit_message_diff_git = __esm({
17187
17735
  });
17188
17736
 
17189
17737
  // ../packages/core/dist/service/local-target/doctor-checks.js
17190
- import { execFileSync as execFileSync4 } from "node:child_process";
17738
+ import { execFileSync as execFileSync5 } from "node:child_process";
17191
17739
  function commandOnPath(command, args) {
17192
17740
  try {
17193
- const detail = execFileSync4(command, args, {
17741
+ const detail = execFileSync5(command, args, {
17194
17742
  encoding: "utf8",
17195
17743
  stdio: ["ignore", "pipe", "ignore"]
17196
17744
  }).trim();
@@ -17222,12 +17770,15 @@ var init_result = __esm({
17222
17770
  });
17223
17771
 
17224
17772
  // ../packages/core/dist/service/local-target/in-process-provider.js
17225
- import { existsSync as existsSync19 } from "node:fs";
17773
+ import { existsSync as existsSync20 } from "node:fs";
17226
17774
  var InProcessProvider;
17227
17775
  var init_in_process_provider = __esm({
17228
17776
  "../packages/core/dist/service/local-target/in-process-provider.js"() {
17229
17777
  "use strict";
17230
17778
  init_git_tree();
17779
+ init_latch_discovery();
17780
+ init_latch_session();
17781
+ init_terminal_profile_types2();
17231
17782
  init_branch_actions_git();
17232
17783
  init_branch_status_git();
17233
17784
  init_commit_message_diff_git();
@@ -17250,7 +17801,7 @@ var init_in_process_provider = __esm({
17250
17801
  */
17251
17802
  async observeResource(input) {
17252
17803
  const observedAt = (/* @__PURE__ */ new Date()).toISOString();
17253
- const state = existsSync19(input.path) ? "available" : "missing";
17804
+ const state = existsSync20(input.path) ? "available" : "missing";
17254
17805
  return ok(this.target, { state, observedAt });
17255
17806
  }
17256
17807
  /**
@@ -17357,6 +17908,50 @@ var init_in_process_provider = __esm({
17357
17908
  async launchAgent(_input) {
17358
17909
  return fail(this.target, "CAPABILITY_NOT_IMPLEMENTED", "Agent launch is owned by the CLI runner (`ovld runner` / `ovld launch`).");
17359
17910
  }
17911
+ // ---- routed (coo:702) ------------------------------------------------
17912
+ /**
17913
+ * Read-only Latch probe on this machine. In-process is the transport that can
17914
+ * honestly answer it: the provider only exists here when the caller device is
17915
+ * the execution target, so the probe runs where the agent process would run.
17916
+ */
17917
+ async discoverLatch(input) {
17918
+ const executable = input.executable?.trim() || DEFAULT_LATCH_EXECUTABLE;
17919
+ try {
17920
+ const result = discoverLatchForExecutionTarget({
17921
+ // A resolved provider carries the target id; the desktop bridge and dev
17922
+ // proxy do not, so they pass the caller's id to share one cache entry
17923
+ // with the runner probe on the same device.
17924
+ executionTargetId: this.target.executionTargetId ?? (input.executionTargetId?.trim() || "local"),
17925
+ executable,
17926
+ cacheFilePath: defaultLatchDiscoveryCachePath(),
17927
+ force: input.force === true
17928
+ });
17929
+ return ok(this.target, result);
17930
+ } catch (error) {
17931
+ return fail(this.target, "TARGET_OPERATION_FAILED", error instanceof Error ? error.message : "Latch discovery failed on this device.");
17932
+ }
17933
+ }
17934
+ async inspectLatchSession(input) {
17935
+ try {
17936
+ return ok(this.target, inspectLatchSession(input));
17937
+ } catch (error) {
17938
+ return fail(this.target, "TARGET_OPERATION_FAILED", error instanceof Error ? error.message : "Could not inspect the Latch session.");
17939
+ }
17940
+ }
17941
+ async openLatchSession(input) {
17942
+ try {
17943
+ return ok(this.target, openLatchSession(input));
17944
+ } catch (error) {
17945
+ return fail(this.target, "TARGET_OPERATION_FAILED", error instanceof Error ? error.message : "Could not open the Latch session.");
17946
+ }
17947
+ }
17948
+ async stopLatchSession(input) {
17949
+ try {
17950
+ return ok(this.target, stopLatchSession(input));
17951
+ } catch (error) {
17952
+ return fail(this.target, "TARGET_OPERATION_FAILED", error instanceof Error ? error.message : "Could not stop the Latch session.");
17953
+ }
17954
+ }
17360
17955
  async doctor() {
17361
17956
  return ok(this.target, { checks: runLocalTargetDoctorChecks() });
17362
17957
  }
@@ -17497,7 +18092,7 @@ var init_local_target_mutation_runner = __esm({
17497
18092
  });
17498
18093
 
17499
18094
  // ../packages/core/dist/service/project-resource-key.js
17500
- import path18 from "node:path";
18095
+ import path19 from "node:path";
17501
18096
  function deriveProjectResourceKey({ resourceKey, label, directoryPath }) {
17502
18097
  const explicit = resourceKey?.trim();
17503
18098
  if (explicit)
@@ -17505,7 +18100,7 @@ function deriveProjectResourceKey({ resourceKey, label, directoryPath }) {
17505
18100
  const labelKey = label?.trim();
17506
18101
  if (labelKey)
17507
18102
  return slugify(labelKey);
17508
- return slugify(path18.basename(path18.resolve(directoryPath)));
18103
+ return slugify(path19.basename(path19.resolve(directoryPath)));
17509
18104
  }
17510
18105
  var init_project_resource_key = __esm({
17511
18106
  "../packages/core/dist/service/project-resource-key.js"() {
@@ -17515,7 +18110,7 @@ var init_project_resource_key = __esm({
17515
18110
  });
17516
18111
 
17517
18112
  // src/branch-planning.ts
17518
- import path19 from "node:path";
18113
+ import path20 from "node:path";
17519
18114
  function stripCombiningMarks(value) {
17520
18115
  return value.normalize("NFKD").replace(/[\u0300-\u036f]/g, "");
17521
18116
  }
@@ -17548,7 +18143,7 @@ function missionWorktreePath({
17548
18143
  branch
17549
18144
  }) {
17550
18145
  const key = resourceKey.trim() || "project";
17551
- return path19.join(worktreeRoot, projectSlug || "project", key, branchLeaf(branch));
18146
+ return path20.join(worktreeRoot, projectSlug || "project", key, branchLeaf(branch));
17552
18147
  }
17553
18148
  function normalizeRemoteRef(ref) {
17554
18149
  return ref.replace(/^origin\//, "").replace(/^refs\/heads\//, "").replace(/^refs\/remotes\/origin\//, "");
@@ -17622,13 +18217,13 @@ var init_branch_planning = __esm({
17622
18217
  });
17623
18218
 
17624
18219
  // 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";
18220
+ import { execFileSync as execFileSync6 } from "node:child_process";
18221
+ import { existsSync as existsSync21, mkdirSync as mkdirSync10, statSync as statSync5 } from "node:fs";
18222
+ import os4 from "node:os";
18223
+ import path21 from "node:path";
17629
18224
  function runGit3(cwd, args, options = {}) {
17630
18225
  try {
17631
- return execFileSync5("git", args, {
18226
+ return execFileSync6("git", args, {
17632
18227
  cwd,
17633
18228
  encoding: "utf8",
17634
18229
  stdio: ["ignore", "pipe", "pipe"],
@@ -17646,7 +18241,7 @@ function lines(value) {
17646
18241
  function resolveGitRoot2(workingDirectory) {
17647
18242
  const root = runGit3(workingDirectory, ["rev-parse", "--show-toplevel"]);
17648
18243
  if (!root) throw new Error(`${workingDirectory} is not inside a git repository.`);
17649
- return path20.resolve(root);
18244
+ return path21.resolve(root);
17650
18245
  }
17651
18246
  function repoDefaultBranch(gitRoot) {
17652
18247
  const symbolic = runGit3(gitRoot, ["symbolic-ref", "--short", "refs/remotes/origin/HEAD"], {
@@ -17781,9 +18376,9 @@ function missionSequence(mission, missionId) {
17781
18376
  }
17782
18377
  function resolveWorktreeRoot() {
17783
18378
  const override = process.env.OVERLORD_WORKTREE_ROOT?.trim();
17784
- if (override) return path20.resolve(override);
18379
+ if (override) return path21.resolve(override);
17785
18380
  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");
18381
+ return path21.join(home ? path21.resolve(home) : path21.join(os4.homedir(), ".ovld"), "worktrees");
17787
18382
  }
17788
18383
  function ensureBranchRef(gitRoot, decision) {
17789
18384
  if (decision.action === "reuse") return;
@@ -17794,9 +18389,9 @@ function ensureBranchRef(gitRoot, decision) {
17794
18389
  }
17795
18390
  function ensureWorktree(gitRoot, decision) {
17796
18391
  ensureBranchRef(gitRoot, decision);
17797
- mkdirSync9(path20.dirname(decision.worktreePath), { recursive: true });
17798
- if (existsSync20(decision.worktreePath)) {
17799
- if (!statSync4(decision.worktreePath).isDirectory()) {
18392
+ mkdirSync10(path21.dirname(decision.worktreePath), { recursive: true });
18393
+ if (existsSync21(decision.worktreePath)) {
18394
+ if (!statSync5(decision.worktreePath).isDirectory()) {
17800
18395
  throw new Error(`Worktree path exists and is not a directory: ${decision.worktreePath}`);
17801
18396
  }
17802
18397
  const existingBranch = worktreeBranch(decision.worktreePath);
@@ -17936,7 +18531,7 @@ var init_branch_preparation = __esm({
17936
18531
  });
17937
18532
 
17938
18533
  // src/discover-project-local.ts
17939
- import path21 from "node:path";
18534
+ import path22 from "node:path";
17940
18535
  async function resolvePreferredExecutionTargetId({
17941
18536
  backend
17942
18537
  }) {
@@ -17953,9 +18548,9 @@ function discoverProjectJsonFromFilesystem({
17953
18548
  workingDirectory,
17954
18549
  preferredExecutionTargetId
17955
18550
  }) {
17956
- let current = path21.resolve(workingDirectory);
18551
+ let current = path22.resolve(workingDirectory);
17957
18552
  while (true) {
17958
- const projectJsonPath = path21.join(current, ".overlord", "project.json");
18553
+ const projectJsonPath = path22.join(current, ".overlord", "project.json");
17959
18554
  const raw = readProjectJsonLink(projectJsonPath, { preferredExecutionTargetId });
17960
18555
  if (raw) {
17961
18556
  return {
@@ -17965,7 +18560,7 @@ function discoverProjectJsonFromFilesystem({
17965
18560
  isPrimary: raw.isPrimary
17966
18561
  };
17967
18562
  }
17968
- const parent = path21.dirname(current);
18563
+ const parent = path22.dirname(current);
17969
18564
  if (parent === current) break;
17970
18565
  current = parent;
17971
18566
  }
@@ -17975,16 +18570,16 @@ async function resolveProjectByIdOrName({
17975
18570
  backend,
17976
18571
  projectRef
17977
18572
  }) {
17978
- const trimmed = projectRef.trim();
18573
+ const trimmed5 = projectRef.trim();
17979
18574
  try {
17980
- return await backend.get(`/api/projects/${encodeURIComponent(trimmed)}`);
18575
+ return await backend.get(`/api/projects/${encodeURIComponent(trimmed5)}`);
17981
18576
  } catch (error) {
17982
18577
  if (!(error instanceof CliError) || !/project not found/i.test(error.message)) throw error;
17983
18578
  }
17984
18579
  const projects = await listAccessibleProjects({ backend });
17985
- const match = projects.find((project) => project.name === trimmed) ?? projects.find((project) => project.slug === trimmed);
18580
+ const match = projects.find((project) => project.name === trimmed5) ?? projects.find((project) => project.slug === trimmed5);
17986
18581
  if (!match) {
17987
- throw new CliError({ message: `Project not found: ${trimmed}` });
18582
+ throw new CliError({ message: `Project not found: ${trimmed5}` });
17988
18583
  }
17989
18584
  return match;
17990
18585
  }
@@ -18025,7 +18620,7 @@ async function discoverProjectOnClient({
18025
18620
  const resolvedLocal = localWithTarget ?? local;
18026
18621
  if (!resolvedLocal) {
18027
18622
  throw new CliError({
18028
- message: `No linked Overlord project found for ${path21.resolve(workingDirectory)}. Run \`ovld add-cwd\` or \`ovld create-project\`.`
18623
+ message: `No linked Overlord project found for ${path22.resolve(workingDirectory)}. Run \`ovld add-cwd\` or \`ovld create-project\`.`
18029
18624
  });
18030
18625
  }
18031
18626
  const project = await resolveProjectByIdOrName({ backend, projectRef: resolvedLocal.projectId });
@@ -18045,6 +18640,134 @@ var init_discover_project_local = __esm({
18045
18640
  }
18046
18641
  });
18047
18642
 
18643
+ // src/latch-discovery.ts
18644
+ import path23 from "node:path";
18645
+ function latchDiscoveryCachePath(dataDir = resolveGlobalDataDir()) {
18646
+ return path23.join(dataDir, LATCH_DISCOVERY_CACHE_FILENAME);
18647
+ }
18648
+ function discoverLatchOnThisDevice({
18649
+ executionTargetId,
18650
+ executable = DEFAULT_LATCH_EXECUTABLE,
18651
+ force = false
18652
+ }) {
18653
+ return discoverLatchForExecutionTarget({
18654
+ executionTargetId,
18655
+ executable,
18656
+ cacheFilePath: latchDiscoveryCachePath(),
18657
+ force
18658
+ });
18659
+ }
18660
+ var init_latch_discovery2 = __esm({
18661
+ "src/latch-discovery.ts"() {
18662
+ "use strict";
18663
+ init_latch_discovery();
18664
+ init_terminal_profile_types2();
18665
+ init_config();
18666
+ }
18667
+ });
18668
+
18669
+ // src/latch-launch.ts
18670
+ import { spawnSync as spawnSync3 } from "node:child_process";
18671
+ function spawnLatchJson({
18672
+ executable,
18673
+ args,
18674
+ stdin
18675
+ }) {
18676
+ const result = spawnSync3(executable, args, {
18677
+ encoding: "utf8",
18678
+ input: stdin,
18679
+ env: process.env,
18680
+ maxBuffer: 2 * 1024 * 1024
18681
+ });
18682
+ return {
18683
+ status: result.status,
18684
+ stdout: result.stdout ?? "",
18685
+ stderr: result.stderr ?? ""
18686
+ };
18687
+ }
18688
+ function createLatchSession({
18689
+ executable = DEFAULT_LATCH_EXECUTABLE,
18690
+ commandString,
18691
+ cwd,
18692
+ env,
18693
+ title,
18694
+ name,
18695
+ commandLabel,
18696
+ externalRunId,
18697
+ executionTargetId,
18698
+ shell = process.env.SHELL?.trim() || "/bin/bash"
18699
+ }) {
18700
+ const manifest = buildLatchCreateManifest({
18701
+ commandString,
18702
+ shell,
18703
+ cwd,
18704
+ env,
18705
+ title,
18706
+ name,
18707
+ commandLabel,
18708
+ externalRunId
18709
+ });
18710
+ const result = spawnLatchJson({
18711
+ executable,
18712
+ args: ["create", "--manifest-file", "-", "--json"],
18713
+ stdin: `${JSON.stringify(manifest)}
18714
+ `
18715
+ });
18716
+ if (result.status !== 0) {
18717
+ const detail = (result.stderr || result.stdout || `exit ${result.status ?? "null"}`).trim();
18718
+ throw new Error(`latch create failed: ${detail}`);
18719
+ }
18720
+ const report = parseLatchCreateReport(result.stdout);
18721
+ if (!report) {
18722
+ throw new Error(
18723
+ `latch create returned unusable JSON: ${(result.stdout || result.stderr).trim() || "(empty)"}`
18724
+ );
18725
+ }
18726
+ return {
18727
+ report,
18728
+ providerSession: toExecutionProviderSession({
18729
+ createReport: report,
18730
+ executionTargetId
18731
+ }),
18732
+ executable
18733
+ };
18734
+ }
18735
+ function openLatchViewer({
18736
+ executable = DEFAULT_LATCH_EXECUTABLE,
18737
+ providerSessionId,
18738
+ viewerKind
18739
+ }) {
18740
+ const viewer = latchViewerFlagForKind(viewerKind);
18741
+ const attachCommand = latchAttachCommand({ executable, providerSessionId });
18742
+ if (!viewer) {
18743
+ return {
18744
+ ok: false,
18745
+ warning: `Latch has no viewer for kind "${viewerKind ?? "unknown"}"; session is running \u2014 attach with: ${attachCommand}`,
18746
+ attachCommand
18747
+ };
18748
+ }
18749
+ const result = spawnLatchJson({
18750
+ executable,
18751
+ args: ["open", providerSessionId, "--with", viewer, "--json"]
18752
+ });
18753
+ if (result.status !== 0) {
18754
+ const detail = (result.stderr || result.stdout || `exit ${result.status ?? "null"}`).trim();
18755
+ return {
18756
+ ok: false,
18757
+ warning: `latch open failed (${detail}); session is running \u2014 attach with: ${attachCommand}`,
18758
+ attachCommand
18759
+ };
18760
+ }
18761
+ return { ok: true, viewer };
18762
+ }
18763
+ var init_latch_launch2 = __esm({
18764
+ "src/latch-launch.ts"() {
18765
+ "use strict";
18766
+ init_latch_launch();
18767
+ init_terminal_profile_types2();
18768
+ }
18769
+ });
18770
+
18048
18771
  // src/pre-launch.ts
18049
18772
  function substitutePreLaunchVariables(commands, variables) {
18050
18773
  return commands.map(
@@ -18072,10 +18795,10 @@ function primaryResourcePath(projectResources) {
18072
18795
  for (const entry of projectResources) {
18073
18796
  if (!entry || typeof entry !== "object") continue;
18074
18797
  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;
18798
+ const path34 = typeof record.path === "string" ? record.path.trim() : "";
18799
+ if (!path34) continue;
18800
+ if (record.isPrimary === true) return path34;
18801
+ if (record.isCurrent === true && !currentPath) currentPath = path34;
18079
18802
  }
18080
18803
  return currentPath;
18081
18804
  }
@@ -18175,7 +18898,7 @@ function terminalInnerCommand({
18175
18898
  const invocation = withPreLaunchCommands(agentCommand, preLaunchCommands);
18176
18899
  return `cd ${shellQuote2(workingDirectory)} && ${exports}; ${invocation}`;
18177
18900
  }
18178
- function terminalLaunchScriptContent({
18901
+ function composeAgentTerminalCommand({
18179
18902
  command,
18180
18903
  args,
18181
18904
  workingDirectory,
@@ -18184,8 +18907,25 @@ function terminalLaunchScriptContent({
18184
18907
  preLaunchCommands
18185
18908
  }) {
18186
18909
  const agentCommand = agentShellCommand({ command, args, preCommand });
18910
+ return terminalInnerCommand({ workingDirectory, agentCommand, extraEnv, preLaunchCommands });
18911
+ }
18912
+ function terminalLaunchScriptContent({
18913
+ command,
18914
+ args,
18915
+ workingDirectory,
18916
+ preCommand,
18917
+ extraEnv = {},
18918
+ preLaunchCommands
18919
+ }) {
18187
18920
  return `#!/usr/bin/env bash
18188
- ${terminalInnerCommand({ workingDirectory, agentCommand, extraEnv, preLaunchCommands })}
18921
+ ${composeAgentTerminalCommand({
18922
+ command,
18923
+ args,
18924
+ workingDirectory,
18925
+ preCommand,
18926
+ extraEnv,
18927
+ preLaunchCommands
18928
+ })}
18189
18929
  `;
18190
18930
  }
18191
18931
  function terminalScriptCommand(scriptPath) {
@@ -18426,9 +19166,9 @@ var init_terminal_launcher = __esm({
18426
19166
  });
18427
19167
 
18428
19168
  // 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";
19169
+ import { spawnSync as spawnSync4 } from "node:child_process";
19170
+ import { chmodSync as chmodSync4, writeFileSync as writeFileSync9 } from "node:fs";
19171
+ import path24 from "node:path";
18432
19172
  function overlordLaunchEnv({
18433
19173
  backendUrl,
18434
19174
  missionId,
@@ -18594,7 +19334,7 @@ function launchScriptPath({
18594
19334
  executionRequestId
18595
19335
  }) {
18596
19336
  const requestPart = executionRequestId ? safeLaunchScriptPart(executionRequestId) : `${process.pid}`;
18597
- return path22.join(tmpDir, `launch-${safeLaunchScriptPart(displayId)}-${requestPart}.sh`);
19337
+ return path24.join(tmpDir, `launch-${safeLaunchScriptPart(displayId)}-${requestPart}.sh`);
18598
19338
  }
18599
19339
  async function buildLaunchPlan({
18600
19340
  runtime,
@@ -18603,12 +19343,12 @@ async function buildLaunchPlan({
18603
19343
  const context = await loadMissionContext({ runtime, missionId: options.missionId });
18604
19344
  pruneStaleProjectTmp({ workingDirectory: options.workingDirectory, create: true });
18605
19345
  const tmpDir = ensureProjectTmpDir(options.workingDirectory);
18606
- const contextFile = path22.join(
19346
+ const contextFile = path24.join(
18607
19347
  tmpDir,
18608
19348
  `mission-${context.displayId.replace(/[^a-zA-Z0-9_-]/g, "-")}.md`
18609
19349
  );
18610
19350
  const launchContext = context.launchContext;
18611
- writeFileSync8(contextFile, `${launchContext}
19351
+ writeFileSync9(contextFile, `${launchContext}
18612
19352
  `);
18613
19353
  const projectResources = await loadProjectResourcesForLaunch({
18614
19354
  runtime,
@@ -18653,13 +19393,21 @@ async function buildLaunchPlan({
18653
19393
  contextFile,
18654
19394
  launchMessage: `Attach to ovld mission ${context.displayId}, then immediately execute ${context.title}. Do not wait for more instructions.`
18655
19395
  });
19396
+ const latchCommandString = composeAgentTerminalCommand({
19397
+ command: command.command,
19398
+ args: command.args,
19399
+ workingDirectory: options.workingDirectory,
19400
+ preCommand: options.preCommand,
19401
+ extraEnv: exportedEnv,
19402
+ preLaunchCommands
19403
+ });
18656
19404
  const terminalScriptPath = options.terminalLauncher?.trim() ? launchScriptPath({
18657
19405
  tmpDir,
18658
19406
  displayId: context.displayId,
18659
19407
  executionRequestId: options.executionRequestId
18660
19408
  }) : null;
18661
19409
  if (terminalScriptPath) {
18662
- writeFileSync8(
19410
+ writeFileSync9(
18663
19411
  terminalScriptPath,
18664
19412
  terminalLaunchScriptContent({
18665
19413
  command: command.command,
@@ -18691,7 +19439,11 @@ async function buildLaunchPlan({
18691
19439
  contextFile,
18692
19440
  workingDirectory: options.workingDirectory,
18693
19441
  execution,
18694
- env: exportedEnv
19442
+ env: exportedEnv,
19443
+ latchCommandString,
19444
+ launchSession: options.launchSession ?? null,
19445
+ missionTitle: options.missionTitle ?? context.title,
19446
+ missionDisplayId: options.missionDisplayId ?? context.displayId
18695
19447
  };
18696
19448
  }
18697
19449
  async function launchAgent({
@@ -18707,26 +19459,130 @@ async function launchAgent({
18707
19459
  ...tmpEnvFor(options.workingDirectory),
18708
19460
  ...plan.env
18709
19461
  };
19462
+ const snapshot = options.launchSession ?? plan.launchSession ?? null;
19463
+ const providerKind = snapshot?.executionProvider.kind ?? "direct";
19464
+ const executable = snapshot?.executionProvider.executable ?? "latch";
19465
+ let providerFallbackWarning = null;
19466
+ let useLatch = false;
19467
+ let resolvedLatchExecutable = executable;
19468
+ const existingProviderSession = providerKind === "latch" ? existingLatchProviderSession({
19469
+ latchSessionId: process.env.LATCH_SESSION_ID,
19470
+ executionTargetId: options.executionTargetId
19471
+ }) : null;
19472
+ if (existingProviderSession && plan.latchCommandString) {
19473
+ const shell = process.env.SHELL?.trim() || "/bin/bash";
19474
+ const result2 = spawnSync4(shell, ["-lc", plan.latchCommandString], {
19475
+ cwd: options.workingDirectory,
19476
+ env,
19477
+ stdio: "inherit"
19478
+ });
19479
+ return {
19480
+ plan: {
19481
+ ...plan,
19482
+ execution: {
19483
+ command: shell,
19484
+ args: ["-lc", plan.latchCommandString],
19485
+ useShell: false,
19486
+ terminal: null,
19487
+ display: `Latch session ${existingProviderSession.providerSessionId} (inline) \u203A ${plan.latchCommandString}`
19488
+ }
19489
+ },
19490
+ status: result2.status,
19491
+ signal: result2.signal,
19492
+ providerSession: existingProviderSession,
19493
+ viewerOpen: null,
19494
+ providerFallbackWarning
19495
+ };
19496
+ }
19497
+ if (providerKind === "latch") {
19498
+ if (!options.executionTargetId) {
19499
+ providerFallbackWarning = "Latch provider selected but no execution target id is available; falling back to direct launch.";
19500
+ } else {
19501
+ const discovery = discoverLatchOnThisDevice({
19502
+ executionTargetId: options.executionTargetId,
19503
+ executable
19504
+ });
19505
+ useLatch = shouldUseLatchProvider({
19506
+ providerKind,
19507
+ latchSelectable: discovery.latchSelectable
19508
+ });
19509
+ if (useLatch && discovery.state === "found") {
19510
+ resolvedLatchExecutable = discovery.resolvedPath;
19511
+ }
19512
+ if (!useLatch) {
19513
+ 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.";
19514
+ }
19515
+ }
19516
+ }
19517
+ if (useLatch && plan.latchCommandString) {
19518
+ const created = createLatchSession({
19519
+ executable: resolvedLatchExecutable,
19520
+ commandString: plan.latchCommandString,
19521
+ cwd: options.workingDirectory,
19522
+ env: plan.env,
19523
+ title: plan.missionTitle,
19524
+ name: plan.missionDisplayId,
19525
+ commandLabel: options.agent,
19526
+ externalRunId: options.executionRequestId,
19527
+ executionTargetId: options.executionTargetId
19528
+ });
19529
+ let viewerOpen = null;
19530
+ const openOnLaunch = snapshot?.viewer.openOnLaunch !== false;
19531
+ if (openOnLaunch) {
19532
+ viewerOpen = openLatchViewer({
19533
+ executable: resolvedLatchExecutable,
19534
+ providerSessionId: created.providerSession.providerSessionId,
19535
+ viewerKind: snapshot?.viewer.kind ?? "iterm"
19536
+ });
19537
+ }
19538
+ return {
19539
+ plan: {
19540
+ ...plan,
19541
+ execution: {
19542
+ command: resolvedLatchExecutable,
19543
+ args: ["create", "--manifest-file", "-", "--json"],
19544
+ useShell: false,
19545
+ terminal: snapshot?.viewer.launcher ?? null,
19546
+ display: `latch create \u203A ${plan.latchCommandString}`
19547
+ }
19548
+ },
19549
+ status: 0,
19550
+ signal: null,
19551
+ providerSession: created.providerSession,
19552
+ viewerOpen,
19553
+ providerFallbackWarning
19554
+ };
19555
+ }
18710
19556
  const { execution } = plan;
18711
- const result = execution.useShell ? spawnSync2(execution.command, {
19557
+ const result = execution.useShell ? spawnSync4(execution.command, {
18712
19558
  cwd: options.workingDirectory,
18713
19559
  env,
18714
19560
  shell: true,
18715
19561
  stdio: "inherit"
18716
- }) : spawnSync2(execution.command, execution.args, {
19562
+ }) : spawnSync4(execution.command, execution.args, {
18717
19563
  cwd: options.workingDirectory,
18718
19564
  env,
18719
19565
  stdio: "inherit"
18720
19566
  });
18721
- return { plan, status: result.status, signal: result.signal };
19567
+ return {
19568
+ plan,
19569
+ status: result.status,
19570
+ signal: result.signal,
19571
+ providerSession: null,
19572
+ viewerOpen: null,
19573
+ providerFallbackWarning
19574
+ };
18722
19575
  }
18723
19576
  var AGENT_HISTORY_EXCLUDED_EVENT_TYPES, EXECUTION_DIRECTIVE;
18724
19577
  var init_launch = __esm({
18725
19578
  "src/launch.ts"() {
18726
19579
  "use strict";
18727
19580
  init_dist2();
19581
+ init_latch_launch();
18728
19582
  init_channel();
18729
19583
  init_agent_binaries();
19584
+ init_latch_discovery2();
19585
+ init_latch_launch2();
18730
19586
  init_pre_launch();
18731
19587
  init_project_tmp();
18732
19588
  init_terminal_launcher();
@@ -18740,8 +19596,8 @@ var init_launch = __esm({
18740
19596
  });
18741
19597
 
18742
19598
  // 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";
19599
+ import { existsSync as existsSync22, readdirSync as readdirSync4, readFileSync as readFileSync16, statSync as statSync6 } from "node:fs";
19600
+ import path25 from "node:path";
18745
19601
  function firstCapture(match) {
18746
19602
  if (!match) return null;
18747
19603
  const value = match[1] ?? match[2] ?? match[3] ?? null;
@@ -18762,15 +19618,15 @@ function recoverLaunchBootstrapFromProjectTmp({
18762
19618
  const trimmedMission = missionId.trim();
18763
19619
  if (!trimmedMission) return empty;
18764
19620
  const tmpDir = projectTmpDir(workingDirectory);
18765
- if (!existsSync21(tmpDir)) return empty;
19621
+ if (!existsSync22(tmpDir)) return empty;
18766
19622
  const prefix = `launch-${safeMissionPart(trimmedMission)}-`;
18767
19623
  let newest = null;
18768
19624
  try {
18769
19625
  for (const name of readdirSync4(tmpDir)) {
18770
19626
  if (!name.startsWith(prefix) || !name.endsWith(".sh")) continue;
18771
- const filePath = path23.join(tmpDir, name);
19627
+ const filePath = path25.join(tmpDir, name);
18772
19628
  try {
18773
- const mtimeMs = statSync5(filePath).mtimeMs;
19629
+ const mtimeMs = statSync6(filePath).mtimeMs;
18774
19630
  if (!newest || mtimeMs > newest.mtimeMs) {
18775
19631
  newest = { path: filePath, mtimeMs };
18776
19632
  }
@@ -18783,7 +19639,7 @@ function recoverLaunchBootstrapFromProjectTmp({
18783
19639
  if (!newest) return empty;
18784
19640
  let contents = "";
18785
19641
  try {
18786
- contents = readFileSync15(newest.path, "utf8");
19642
+ contents = readFileSync16(newest.path, "utf8");
18787
19643
  } catch {
18788
19644
  return empty;
18789
19645
  }
@@ -18804,8 +19660,8 @@ var init_launch_bootstrap = __esm({
18804
19660
  });
18805
19661
 
18806
19662
  // src/org-setup.ts
18807
- import { readFileSync as readFileSync16 } from "node:fs";
18808
- import path24 from "node:path";
19663
+ import { readFileSync as readFileSync17 } from "node:fs";
19664
+ import path26 from "node:path";
18809
19665
  import { createInterface as createInterface3 } from "node:readline";
18810
19666
  function suggestSlug(name) {
18811
19667
  const cleaned = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
@@ -18820,8 +19676,8 @@ function promptText({
18820
19676
  return new Promise((resolve) => {
18821
19677
  rl.question(`${question}${suffix}: `, (answer) => {
18822
19678
  rl.close();
18823
- const trimmed = answer.trim();
18824
- resolve(trimmed || defaultValue || "");
19679
+ const trimmed5 = answer.trim();
19680
+ resolve(trimmed5 || defaultValue || "");
18825
19681
  });
18826
19682
  });
18827
19683
  }
@@ -18884,12 +19740,12 @@ async function runOrgSetupCommand({
18884
19740
  let logoWarning = null;
18885
19741
  if (logoPath) {
18886
19742
  try {
18887
- const resolvedPath = path24.resolve(logoPath);
18888
- const bytes = readFileSync16(resolvedPath);
19743
+ const resolvedPath = path26.resolve(logoPath);
19744
+ const bytes = readFileSync17(resolvedPath);
18889
19745
  const stored = await runtime.backend.postRaw({
18890
19746
  path: "/api/uploads/organization-images",
18891
19747
  body: bytes,
18892
- filename: path24.basename(resolvedPath)
19748
+ filename: path26.basename(resolvedPath)
18893
19749
  });
18894
19750
  await runtime.backend.patch({
18895
19751
  path: `/api/organizations/${encodeURIComponent(organization.id)}`,
@@ -19384,17 +20240,17 @@ var init_protocol_help = __esm({
19384
20240
 
19385
20241
  // src/vcs-sessions.ts
19386
20242
  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";
20243
+ import { existsSync as existsSync23, mkdirSync as mkdirSync11, readFileSync as readFileSync18, writeFileSync as writeFileSync10 } from "node:fs";
20244
+ import path27 from "node:path";
19389
20245
  function manifestPath2(workingDirectory) {
19390
- const key = createHash8("sha256").update(path25.resolve(workingDirectory)).digest("hex");
19391
- return path25.join(resolveGlobalDataDir(), "vcs-sessions", `${key}.json`);
20246
+ const key = createHash8("sha256").update(path27.resolve(workingDirectory)).digest("hex");
20247
+ return path27.join(resolveGlobalDataDir(), "vcs-sessions", `${key}.json`);
19392
20248
  }
19393
20249
  function readEntries(workingDirectory) {
19394
20250
  try {
19395
20251
  const target = manifestPath2(workingDirectory);
19396
- if (!existsSync22(target)) return [];
19397
- const raw = JSON.parse(readFileSync17(target, "utf8"));
20252
+ if (!existsSync23(target)) return [];
20253
+ const raw = JSON.parse(readFileSync18(target, "utf8"));
19398
20254
  if (!Array.isArray(raw.entries)) return [];
19399
20255
  const now = Date.now();
19400
20256
  return raw.entries.flatMap((entry) => {
@@ -19413,8 +20269,8 @@ function readEntries(workingDirectory) {
19413
20269
  function writeEntries(workingDirectory, entries) {
19414
20270
  try {
19415
20271
  const target = manifestPath2(workingDirectory);
19416
- mkdirSync10(path25.dirname(target), { recursive: true });
19417
- writeFileSync9(target, JSON.stringify({ entries }));
20272
+ mkdirSync11(path27.dirname(target), { recursive: true });
20273
+ writeFileSync10(target, JSON.stringify({ entries }));
19418
20274
  } catch {
19419
20275
  }
19420
20276
  }
@@ -19464,23 +20320,23 @@ var init_vcs_sessions = __esm({
19464
20320
  });
19465
20321
 
19466
20322
  // src/vcs.ts
19467
- import { execFileSync as execFileSync6 } from "node:child_process";
20323
+ import { execFileSync as execFileSync7 } from "node:child_process";
19468
20324
  import { createHash as createHash9 } from "node:crypto";
19469
20325
  import {
19470
- existsSync as existsSync23,
19471
- mkdirSync as mkdirSync11,
20326
+ existsSync as existsSync24,
20327
+ mkdirSync as mkdirSync12,
19472
20328
  readdirSync as readdirSync5,
19473
- readFileSync as readFileSync18,
20329
+ readFileSync as readFileSync19,
19474
20330
  realpathSync as realpathSync3,
19475
20331
  rmSync as rmSync5,
19476
- writeFileSync as writeFileSync10
20332
+ writeFileSync as writeFileSync11
19477
20333
  } from "node:fs";
19478
- import path26 from "node:path";
20334
+ import path28 from "node:path";
19479
20335
  function normalizePath(filePath) {
19480
20336
  return filePath.replace(/\\/g, "/").trim();
19481
20337
  }
19482
20338
  function sameWorkingDirectory(left, right) {
19483
- return typeof left === "string" && path26.resolve(left) === path26.resolve(right);
20339
+ return typeof left === "string" && path28.resolve(left) === path28.resolve(right);
19484
20340
  }
19485
20341
  function parsePorcelainLine(line) {
19486
20342
  const trimmedEnd = line.replace(/\s+$/, "");
@@ -19500,7 +20356,7 @@ function hashWorktreeFile({
19500
20356
  filePath
19501
20357
  }) {
19502
20358
  try {
19503
- return execFileSync6("git", ["hash-object", filePath], {
20359
+ return execFileSync7("git", ["hash-object", filePath], {
19504
20360
  cwd: workingDirectory,
19505
20361
  encoding: "utf8",
19506
20362
  stdio: ["ignore", "pipe", "ignore"]
@@ -19511,7 +20367,7 @@ function hashWorktreeFile({
19511
20367
  }
19512
20368
  function readChangedFiles(workingDirectory) {
19513
20369
  try {
19514
- const output = execFileSync6("git", ["status", "--porcelain"], {
20370
+ const output = execFileSync7("git", ["status", "--porcelain"], {
19515
20371
  cwd: workingDirectory,
19516
20372
  encoding: "utf8",
19517
20373
  stdio: ["ignore", "pipe", "ignore"],
@@ -19531,13 +20387,13 @@ function sessionKeyHash({
19531
20387
  workingDirectory,
19532
20388
  missionId
19533
20389
  }) {
19534
- return createHash9("sha256").update(`${path26.resolve(workingDirectory)}\0${missionId}`).digest("hex");
20390
+ return createHash9("sha256").update(`${path28.resolve(workingDirectory)}\0${missionId}`).digest("hex");
19535
20391
  }
19536
20392
  function baselineFilePath({
19537
20393
  workingDirectory,
19538
20394
  missionId
19539
20395
  }) {
19540
- return path26.join(
20396
+ return path28.join(
19541
20397
  resolveGlobalDataDir(),
19542
20398
  "vcs-baselines",
19543
20399
  `${sessionKeyHash({ workingDirectory, missionId })}.json`
@@ -19547,7 +20403,7 @@ function touchedFilesPath({
19547
20403
  workingDirectory,
19548
20404
  missionId
19549
20405
  }) {
19550
- return path26.join(
20406
+ return path28.join(
19551
20407
  resolveGlobalDataDir(),
19552
20408
  "vcs-touched",
19553
20409
  `${sessionKeyHash({ workingDirectory, missionId })}.json`
@@ -19557,7 +20413,7 @@ function rationaleNotesPath({
19557
20413
  workingDirectory,
19558
20414
  missionId
19559
20415
  }) {
19560
- return path26.join(
20416
+ return path28.join(
19561
20417
  resolveGlobalDataDir(),
19562
20418
  "vcs-rationale-notes",
19563
20419
  `${sessionKeyHash({ workingDirectory, missionId })}.json`
@@ -19567,7 +20423,7 @@ function bashSnapshotPath({
19567
20423
  workingDirectory,
19568
20424
  missionId
19569
20425
  }) {
19570
- return path26.join(
20426
+ return path28.join(
19571
20427
  resolveGlobalDataDir(),
19572
20428
  "vcs-touched",
19573
20429
  `${sessionKeyHash({ workingDirectory, missionId })}.bash-snapshot.json`
@@ -19579,8 +20435,8 @@ function readBashSnapshot({
19579
20435
  }) {
19580
20436
  try {
19581
20437
  const target = bashSnapshotPath({ workingDirectory, missionId });
19582
- if (!existsSync23(target)) return /* @__PURE__ */ new Map();
19583
- const raw = JSON.parse(readFileSync18(target, "utf8"));
20438
+ if (!existsSync24(target)) return /* @__PURE__ */ new Map();
20439
+ const raw = JSON.parse(readFileSync19(target, "utf8"));
19584
20440
  const byPath = /* @__PURE__ */ new Map();
19585
20441
  if (Array.isArray(raw.files)) {
19586
20442
  for (const entry of raw.files) {
@@ -19605,8 +20461,8 @@ function writeBashSnapshot({
19605
20461
  }) {
19606
20462
  try {
19607
20463
  const target = bashSnapshotPath({ workingDirectory, missionId });
19608
- mkdirSync11(path26.dirname(target), { recursive: true });
19609
- writeFileSync10(target, JSON.stringify({ updatedAt: (/* @__PURE__ */ new Date()).toISOString(), files }));
20464
+ mkdirSync12(path28.dirname(target), { recursive: true });
20465
+ writeFileSync11(target, JSON.stringify({ updatedAt: (/* @__PURE__ */ new Date()).toISOString(), files }));
19610
20466
  } catch {
19611
20467
  }
19612
20468
  }
@@ -19639,12 +20495,12 @@ function recordBashObservedChanges({
19639
20495
  }
19640
20496
  }
19641
20497
  function normalizeAbsolute(filePath) {
19642
- const resolved = path26.resolve(filePath);
20498
+ const resolved = path28.resolve(filePath);
19643
20499
  try {
19644
20500
  return realpathSync3(resolved).replace(/\\/g, "/");
19645
20501
  } catch {
19646
20502
  try {
19647
- return path26.join(realpathSync3(path26.dirname(resolved)), path26.basename(resolved)).replace(/\\/g, "/");
20503
+ return path28.join(realpathSync3(path28.dirname(resolved)), path28.basename(resolved)).replace(/\\/g, "/");
19648
20504
  } catch {
19649
20505
  return resolved.replace(/\\/g, "/");
19650
20506
  }
@@ -19652,7 +20508,7 @@ function normalizeAbsolute(filePath) {
19652
20508
  }
19653
20509
  function gitRepoRoot(workingDirectory) {
19654
20510
  try {
19655
- const root = execFileSync6("git", ["rev-parse", "--show-toplevel"], {
20511
+ const root = execFileSync7("git", ["rev-parse", "--show-toplevel"], {
19656
20512
  cwd: workingDirectory,
19657
20513
  encoding: "utf8",
19658
20514
  stdio: ["ignore", "pipe", "ignore"]
@@ -19671,7 +20527,7 @@ function resetTouchedFiles({
19671
20527
  touchedFilesPath({ workingDirectory, missionId }),
19672
20528
  bashSnapshotPath({ workingDirectory, missionId })
19673
20529
  ]) {
19674
- if (existsSync23(target)) rmSync5(target);
20530
+ if (existsSync24(target)) rmSync5(target);
19675
20531
  }
19676
20532
  } catch {
19677
20533
  }
@@ -19682,14 +20538,14 @@ function resetRationaleNotes({
19682
20538
  }) {
19683
20539
  try {
19684
20540
  const target = rationaleNotesPath({ workingDirectory, missionId });
19685
- if (existsSync23(target)) rmSync5(target);
20541
+ if (existsSync24(target)) rmSync5(target);
19686
20542
  } catch {
19687
20543
  }
19688
20544
  }
19689
20545
  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;
20546
+ const trimmed5 = (value ?? "").replace(/\s+/g, " ").trim();
20547
+ if (!trimmed5) return null;
20548
+ return trimmed5.length > max ? `${trimmed5.slice(0, max - 1)}...` : trimmed5;
19693
20549
  }
19694
20550
  function readRationaleNotes({
19695
20551
  workingDirectory,
@@ -19697,8 +20553,8 @@ function readRationaleNotes({
19697
20553
  }) {
19698
20554
  try {
19699
20555
  const target = rationaleNotesPath({ workingDirectory, missionId });
19700
- if (!existsSync23(target)) return [];
19701
- const raw = JSON.parse(readFileSync18(target, "utf8"));
20556
+ if (!existsSync24(target)) return [];
20557
+ const raw = JSON.parse(readFileSync19(target, "utf8"));
19702
20558
  if (!Array.isArray(raw.notes)) return [];
19703
20559
  return raw.notes.flatMap((note) => {
19704
20560
  if (typeof note !== "object" || note === null || typeof note.filePath !== "string") {
@@ -19732,7 +20588,7 @@ function recordRationaleNotes({
19732
20588
  intent: truncateNoteText(note.intent),
19733
20589
  transcriptContext: truncateNoteText(note.transcriptContext)
19734
20590
  })).filter((note) => note.filePath).map((note) => {
19735
- const absolute = normalizeAbsolute(path26.resolve(workingDirectory, note.filePath));
20591
+ const absolute = normalizeAbsolute(path28.resolve(workingDirectory, note.filePath));
19736
20592
  return {
19737
20593
  filePath: absolute,
19738
20594
  toolName: note.toolName,
@@ -19740,17 +20596,17 @@ function recordRationaleNotes({
19740
20596
  transcriptContext: note.transcriptContext,
19741
20597
  contentHash: hashWorktreeFile({
19742
20598
  workingDirectory,
19743
- filePath: path26.relative(workingDirectory, absolute)
20599
+ filePath: path28.relative(workingDirectory, absolute)
19744
20600
  }),
19745
20601
  recordedAt: (/* @__PURE__ */ new Date()).toISOString()
19746
20602
  };
19747
20603
  });
19748
20604
  if (additions.length === 0) return;
19749
20605
  const target = rationaleNotesPath({ workingDirectory, missionId });
19750
- mkdirSync11(path26.dirname(target), { recursive: true });
20606
+ mkdirSync12(path28.dirname(target), { recursive: true });
19751
20607
  const prior = readRationaleNotes({ workingDirectory, missionId });
19752
20608
  const notesToKeep = [...prior, ...additions].slice(-200);
19753
- writeFileSync10(
20609
+ writeFileSync11(
19754
20610
  target,
19755
20611
  JSON.stringify({ updatedAt: (/* @__PURE__ */ new Date()).toISOString(), notes: notesToKeep })
19756
20612
  );
@@ -19763,16 +20619,16 @@ function recordTouchedFiles({
19763
20619
  files
19764
20620
  }) {
19765
20621
  try {
19766
- const additions = files.map((filePath) => (filePath ?? "").trim()).filter(Boolean).map((filePath) => normalizeAbsolute(path26.resolve(workingDirectory, filePath)));
20622
+ const additions = files.map((filePath) => (filePath ?? "").trim()).filter(Boolean).map((filePath) => normalizeAbsolute(path28.resolve(workingDirectory, filePath)));
19767
20623
  if (additions.length === 0) return;
19768
20624
  const target = touchedFilesPath({ workingDirectory, missionId });
19769
- mkdirSync11(path26.dirname(target), { recursive: true });
20625
+ mkdirSync12(path28.dirname(target), { recursive: true });
19770
20626
  const existing = readTouchedLog({ workingDirectory, missionId })?.paths ?? /* @__PURE__ */ new Set();
19771
20627
  for (const filePath of additions) existing.add(filePath);
19772
- writeFileSync10(
20628
+ writeFileSync11(
19773
20629
  target,
19774
20630
  JSON.stringify({
19775
- workingDirectory: path26.resolve(workingDirectory),
20631
+ workingDirectory: path28.resolve(workingDirectory),
19776
20632
  missionId,
19777
20633
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
19778
20634
  paths: Array.from(existing)
@@ -19785,7 +20641,7 @@ function hasTouchedFilesLog({
19785
20641
  workingDirectory,
19786
20642
  missionId
19787
20643
  }) {
19788
- return existsSync23(touchedFilesPath({ workingDirectory, missionId }));
20644
+ return existsSync24(touchedFilesPath({ workingDirectory, missionId }));
19789
20645
  }
19790
20646
  function readTouchedLog({
19791
20647
  workingDirectory,
@@ -19793,8 +20649,8 @@ function readTouchedLog({
19793
20649
  }) {
19794
20650
  try {
19795
20651
  const target = touchedFilesPath({ workingDirectory, missionId });
19796
- if (!existsSync23(target)) return null;
19797
- const raw = JSON.parse(readFileSync18(target, "utf8"));
20652
+ if (!existsSync24(target)) return null;
20653
+ const raw = JSON.parse(readFileSync19(target, "utf8"));
19798
20654
  const result = /* @__PURE__ */ new Set();
19799
20655
  if (Array.isArray(raw.paths)) {
19800
20656
  for (const entry of raw.paths) {
@@ -19827,14 +20683,14 @@ function writeBaseline({
19827
20683
  }) {
19828
20684
  try {
19829
20685
  const target = baselineFilePath({ workingDirectory, missionId });
19830
- mkdirSync11(path26.dirname(target), { recursive: true });
20686
+ mkdirSync12(path28.dirname(target), { recursive: true });
19831
20687
  const snapshot = {
19832
- workingDirectory: path26.resolve(workingDirectory),
20688
+ workingDirectory: path28.resolve(workingDirectory),
19833
20689
  missionId,
19834
20690
  capturedAt: (/* @__PURE__ */ new Date()).toISOString(),
19835
20691
  files: snapshotBaselineFiles({ workingDirectory, files })
19836
20692
  };
19837
- writeFileSync10(target, JSON.stringify(snapshot));
20693
+ writeFileSync11(target, JSON.stringify(snapshot));
19838
20694
  } catch {
19839
20695
  }
19840
20696
  }
@@ -19846,13 +20702,13 @@ function readPeerTouchedClaims({
19846
20702
  readActiveSessions(workingDirectory).map((entry) => entry.missionId.trim()).filter(Boolean)
19847
20703
  );
19848
20704
  if (activeMissionIds.size === 0) return [];
19849
- const directory = path26.join(resolveGlobalDataDir(), "vcs-touched");
19850
- if (!existsSync23(directory)) return [];
20705
+ const directory = path28.join(resolveGlobalDataDir(), "vcs-touched");
20706
+ if (!existsSync24(directory)) return [];
19851
20707
  const claims = [];
19852
20708
  for (const name of readdirSync5(directory)) {
19853
20709
  if (!name.endsWith(".json") || name.endsWith(".bash-snapshot.json")) continue;
19854
20710
  try {
19855
- const raw = JSON.parse(readFileSync18(path26.join(directory, name), "utf8"));
20711
+ const raw = JSON.parse(readFileSync19(path28.join(directory, name), "utf8"));
19856
20712
  const candidateMissionId = typeof raw.missionId === "string" && raw.missionId.trim() ? raw.missionId.trim() : null;
19857
20713
  if (!candidateMissionId || candidateMissionId === missionId) continue;
19858
20714
  if (!activeMissionIds.has(candidateMissionId)) continue;
@@ -19877,8 +20733,8 @@ function readBaselineSnapshot({
19877
20733
  }) {
19878
20734
  try {
19879
20735
  const target = baselineFilePath({ workingDirectory, missionId });
19880
- if (!existsSync23(target)) return /* @__PURE__ */ new Map();
19881
- const raw = JSON.parse(readFileSync18(target, "utf8"));
20736
+ if (!existsSync24(target)) return /* @__PURE__ */ new Map();
20737
+ const raw = JSON.parse(readFileSync19(target, "utf8"));
19882
20738
  if (Array.isArray(raw.files)) {
19883
20739
  const byPath = /* @__PURE__ */ new Map();
19884
20740
  for (const entry of raw.files) {
@@ -19972,10 +20828,10 @@ function compileIgnorePattern(rawPattern) {
19972
20828
  }
19973
20829
  function loadIgnoreRules(repoRoot) {
19974
20830
  try {
19975
- const target = path26.join(repoRoot, OVERLORD_IGNORE_FILENAME);
19976
- if (!existsSync23(target)) return [];
20831
+ const target = path28.join(repoRoot, OVERLORD_IGNORE_FILENAME);
20832
+ if (!existsSync24(target)) return [];
19977
20833
  const rules = [];
19978
- for (const rawLine of readFileSync18(target, "utf8").split("\n")) {
20834
+ for (const rawLine of readFileSync19(target, "utf8").split("\n")) {
19979
20835
  const line = rawLine.replace(/\r$/, "").trim();
19980
20836
  if (!line || line.startsWith("#")) continue;
19981
20837
  const rule = compileIgnorePattern(line);
@@ -20009,7 +20865,7 @@ function filterRunAttributableChanges({
20009
20865
  return [];
20010
20866
  }
20011
20867
  if (!touched) return [{ filePath: entry.filePath, vcsStatus: entry.vcsStatus }];
20012
- const absolute = normalizeAbsolute(path26.resolve(repoRoot, entry.filePath));
20868
+ const absolute = normalizeAbsolute(path28.resolve(repoRoot, entry.filePath));
20013
20869
  if (touched.paths.has(absolute)) {
20014
20870
  return [
20015
20871
  {
@@ -20040,7 +20896,7 @@ function filterRunAttributableChanges({
20040
20896
  });
20041
20897
  }
20042
20898
  function titleFromPath(filePath) {
20043
- const base = path26.basename(filePath).replace(/\.[^.]+$/, "");
20899
+ const base = path28.basename(filePath).replace(/\.[^.]+$/, "");
20044
20900
  const words = base.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[-_]+/g, " ").trim();
20045
20901
  if (!words) return `Update ${filePath}`;
20046
20902
  return `Update ${words.replace(/\b\w/g, (char) => char.toUpperCase())}`;
@@ -20063,7 +20919,7 @@ function draftChangeRationalesFromNotes({
20063
20919
  if (notes.length === 0 || files.length === 0) return [];
20064
20920
  const repoRoot = gitRepoRoot(workingDirectory) ?? workingDirectory;
20065
20921
  return files.flatMap((file) => {
20066
- const absolute = normalizeAbsolute(path26.resolve(repoRoot, file.filePath));
20922
+ const absolute = normalizeAbsolute(path28.resolve(repoRoot, file.filePath));
20067
20923
  const currentHash = hashWorktreeFile({ workingDirectory, filePath: file.filePath });
20068
20924
  const note = latestRelevantNote({ notes, filePath: absolute, currentHash });
20069
20925
  if (!note) return [];
@@ -20103,17 +20959,17 @@ var init_vcs = __esm({
20103
20959
  });
20104
20960
 
20105
20961
  // src/record-touched.ts
20106
- import { readFileSync as readFileSync19 } from "node:fs";
20107
- import path27 from "node:path";
20962
+ import { readFileSync as readFileSync20 } from "node:fs";
20963
+ import path29 from "node:path";
20108
20964
  function collectCandidates(toolInput) {
20109
20965
  const counts = /* @__PURE__ */ new Map();
20110
20966
  const order = [];
20111
20967
  const bump = (raw, amount) => {
20112
20968
  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);
20969
+ const trimmed5 = raw.trim();
20970
+ if (!trimmed5) return;
20971
+ if (!counts.has(trimmed5)) order.push(trimmed5);
20972
+ counts.set(trimmed5, (counts.get(trimmed5) ?? 0) + amount);
20117
20973
  };
20118
20974
  bump(toolInput.file_path, 1);
20119
20975
  bump(toolInput.notebook_path, 1);
@@ -20153,7 +21009,7 @@ function editIntent({
20153
21009
  function recentAssistantContext(transcriptPath) {
20154
21010
  if (typeof transcriptPath !== "string" || !transcriptPath.trim()) return null;
20155
21011
  try {
20156
- const lines2 = readFileSync19(transcriptPath, "utf8").split("\n").slice(-200);
21012
+ const lines2 = readFileSync20(transcriptPath, "utf8").split("\n").slice(-200);
20157
21013
  for (let index = lines2.length - 1; index >= 0; index -= 1) {
20158
21014
  const line = lines2[index]?.trim();
20159
21015
  if (!line) continue;
@@ -20203,7 +21059,7 @@ function recordTouchedFromPayload({
20203
21059
  const toolInput = toolInputRaw && typeof toolInputRaw === "object" ? toolInputRaw : {};
20204
21060
  const toolName = typeof payload.tool_name === "string" && payload.tool_name.trim() ? payload.tool_name.trim() : "file edit";
20205
21061
  const cwd = typeof payload.cwd === "string" && payload.cwd.trim() ? payload.cwd.trim() : fallbackCwd;
20206
- const workingDirectory = path27.resolve(cwd);
21062
+ const workingDirectory = path29.resolve(cwd);
20207
21063
  const trimmedOverride = missionOverride?.trim();
20208
21064
  let missionId;
20209
21065
  let ambiguous = false;
@@ -20307,23 +21163,23 @@ var init_resource_observations = __esm({
20307
21163
 
20308
21164
  // src/runner-identity.ts
20309
21165
  import { randomUUID } from "node:crypto";
20310
- import { existsSync as existsSync24, mkdirSync as mkdirSync12, readFileSync as readFileSync20, writeFileSync as writeFileSync11 } from "node:fs";
21166
+ import { existsSync as existsSync25, mkdirSync as mkdirSync13, readFileSync as readFileSync21, writeFileSync as writeFileSync12 } from "node:fs";
20311
21167
  import { hostname as hostname4 } from "node:os";
20312
- import path28 from "node:path";
21168
+ import path30 from "node:path";
20313
21169
  function envValue(name) {
20314
21170
  const value = process.env[name]?.trim();
20315
21171
  return value && value.length > 0 ? value : null;
20316
21172
  }
20317
21173
  function runnerInstanceStatePath(dataDir = resolveGlobalDataDir()) {
20318
- return path28.join(dataDir, RUNNER_INSTANCE_STATE_FILENAME);
21174
+ return path30.join(dataDir, RUNNER_INSTANCE_STATE_FILENAME);
20319
21175
  }
20320
21176
  function resolveRunnerInstanceId(dataDir = resolveGlobalDataDir()) {
20321
21177
  const pinned = envValue("OVERLORD_RUNNER_INSTANCE_ID");
20322
21178
  if (pinned) return pinned;
20323
21179
  const statePath = runnerInstanceStatePath(dataDir);
20324
- if (existsSync24(statePath)) {
21180
+ if (existsSync25(statePath)) {
20325
21181
  try {
20326
- const parsed = JSON.parse(readFileSync20(statePath, "utf8"));
21182
+ const parsed = JSON.parse(readFileSync21(statePath, "utf8"));
20327
21183
  if (typeof parsed.runnerInstanceId === "string" && parsed.runnerInstanceId.trim()) {
20328
21184
  return parsed.runnerInstanceId.trim();
20329
21185
  }
@@ -20332,8 +21188,8 @@ function resolveRunnerInstanceId(dataDir = resolveGlobalDataDir()) {
20332
21188
  }
20333
21189
  const runnerInstanceId = randomUUID();
20334
21190
  try {
20335
- mkdirSync12(path28.dirname(statePath), { recursive: true });
20336
- writeFileSync11(statePath, `${JSON.stringify({ runnerInstanceId }, null, 2)}
21191
+ mkdirSync13(path30.dirname(statePath), { recursive: true });
21192
+ writeFileSync12(statePath, `${JSON.stringify({ runnerInstanceId }, null, 2)}
20337
21193
  `, { mode: 384 });
20338
21194
  } catch {
20339
21195
  }
@@ -20375,12 +21231,12 @@ var init_runner_identity = __esm({
20375
21231
 
20376
21232
  // src/runner-service.ts
20377
21233
  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";
21234
+ import { chmodSync as chmodSync5, existsSync as existsSync26, mkdirSync as mkdirSync14, readFileSync as readFileSync22, rmSync as rmSync6, writeFileSync as writeFileSync13 } from "node:fs";
21235
+ import os5 from "node:os";
21236
+ import path31 from "node:path";
20381
21237
  import { promisify } from "node:util";
20382
21238
  function writeServiceFile(filePath, contents) {
20383
- writeFileSync12(filePath, contents, { mode: 384 });
21239
+ writeFileSync13(filePath, contents, { mode: 384 });
20384
21240
  chmodSync5(filePath, 384);
20385
21241
  }
20386
21242
  function emptyRunnerServiceState() {
@@ -20399,21 +21255,21 @@ function emptyRunnerServiceState() {
20399
21255
  };
20400
21256
  }
20401
21257
  function runnerServiceStatePath(dataDir = resolveGlobalDataDir()) {
20402
- return path29.join(dataDir, RUNNER_SERVICE_STATE_FILENAME);
21258
+ return path31.join(dataDir, RUNNER_SERVICE_STATE_FILENAME);
20403
21259
  }
20404
21260
  function readRunnerServiceState(dataDir = resolveGlobalDataDir()) {
20405
21261
  const filePath = runnerServiceStatePath(dataDir);
20406
- if (!existsSync25(filePath)) return emptyRunnerServiceState();
21262
+ if (!existsSync26(filePath)) return emptyRunnerServiceState();
20407
21263
  try {
20408
- const parsed = JSON.parse(readFileSync21(filePath, "utf8"));
21264
+ const parsed = JSON.parse(readFileSync22(filePath, "utf8"));
20409
21265
  return { ...emptyRunnerServiceState(), ...parsed };
20410
21266
  } catch {
20411
21267
  return emptyRunnerServiceState();
20412
21268
  }
20413
21269
  }
20414
21270
  function writeRunnerServiceState(state, dataDir = resolveGlobalDataDir()) {
20415
- mkdirSync13(dataDir, { recursive: true });
20416
- writeFileSync12(runnerServiceStatePath(dataDir), `${JSON.stringify(state, null, 2)}
21271
+ mkdirSync14(dataDir, { recursive: true });
21272
+ writeFileSync13(runnerServiceStatePath(dataDir), `${JSON.stringify(state, null, 2)}
20417
21273
  `, "utf8");
20418
21274
  }
20419
21275
  function patchRunnerServiceState(patch, dataDir = resolveGlobalDataDir()) {
@@ -20422,13 +21278,13 @@ function patchRunnerServiceState(patch, dataDir = resolveGlobalDataDir()) {
20422
21278
  return next;
20423
21279
  }
20424
21280
  function runnerFocusStatePath(dataDir = resolveGlobalDataDir()) {
20425
- return path29.join(dataDir, RUNNER_FOCUS_STATE_FILENAME);
21281
+ return path31.join(dataDir, RUNNER_FOCUS_STATE_FILENAME);
20426
21282
  }
20427
21283
  function readDesktopFocusState(dataDir = resolveGlobalDataDir()) {
20428
21284
  const filePath = runnerFocusStatePath(dataDir);
20429
- if (!existsSync25(filePath)) return { lastFocusedAt: null };
21285
+ if (!existsSync26(filePath)) return { lastFocusedAt: null };
20430
21286
  try {
20431
- const parsed = JSON.parse(readFileSync21(filePath, "utf8"));
21287
+ const parsed = JSON.parse(readFileSync22(filePath, "utf8"));
20432
21288
  return { lastFocusedAt: parsed.lastFocusedAt ?? null };
20433
21289
  } catch {
20434
21290
  return { lastFocusedAt: null };
@@ -20458,17 +21314,17 @@ function nextRunnerLastError(pollError) {
20458
21314
  }
20459
21315
  function resolveOverlordAppInvocation({
20460
21316
  platform: platform2 = process.platform,
20461
- homedir: homedir2 = os4.homedir(),
20462
- exists = existsSync25
21317
+ homedir: homedir2 = os5.homedir(),
21318
+ exists = existsSync26
20463
21319
  } = {}) {
20464
21320
  if (platform2 !== "darwin") return null;
20465
21321
  const appDirs = [
20466
21322
  "/Applications/Overlord.app",
20467
- path29.join(homedir2, "Applications", "Overlord.app")
21323
+ path31.join(homedir2, "Applications", "Overlord.app")
20468
21324
  ];
20469
21325
  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");
21326
+ const program = path31.join(appDir, "Contents", "MacOS", "Overlord");
21327
+ const script = path31.join(appDir, "Contents", "Resources", "cli", "bin", "ovld.mjs");
20472
21328
  if (exists(program) && exists(script)) {
20473
21329
  return { program, args: [script, "runner", "supervise"], runAsElectronNode: true };
20474
21330
  }
@@ -20480,7 +21336,7 @@ function resolveOvldInvocation(argv = process.argv, execPath = process.execPath)
20480
21336
  if (override) {
20481
21337
  return { program: override, args: ["runner", "supervise"] };
20482
21338
  }
20483
- const scriptPath = argv[1] ? path29.resolve(argv[1]) : "";
21339
+ const scriptPath = argv[1] ? path31.resolve(argv[1]) : "";
20484
21340
  if (process.env.ELECTRON_RUN_AS_NODE) {
20485
21341
  return scriptPath ? { program: execPath, args: [scriptPath, "runner", "supervise"], runAsElectronNode: true } : { program: execPath, args: ["runner", "supervise"], runAsElectronNode: true };
20486
21342
  }
@@ -20513,7 +21369,7 @@ function buildRunnerServiceEnv({
20513
21369
  PATH: process.env.PATH?.trim() || "/usr/local/bin:/usr/bin:/bin"
20514
21370
  };
20515
21371
  const home = overlordHome?.trim() || process.env.OVLD_HOME?.trim();
20516
- if (home) env.OVLD_HOME = path29.resolve(home);
21372
+ if (home) env.OVLD_HOME = path31.resolve(home);
20517
21373
  const token = process.env.OVERLORD_USER_TOKEN?.trim() || process.env.OVLD_USER_TOKEN?.trim();
20518
21374
  if (token) env.OVERLORD_USER_TOKEN = token;
20519
21375
  if (runAsElectronNode || process.env.ELECTRON_RUN_AS_NODE) env.ELECTRON_RUN_AS_NODE = "1";
@@ -20552,9 +21408,9 @@ ${envEntries}
20552
21408
  <key>KeepAlive</key>
20553
21409
  <true/>
20554
21410
  <key>StandardOutPath</key>
20555
- <string>${xmlEscape(path29.join(logDir, "runner-service.out.log"))}</string>
21411
+ <string>${xmlEscape(path31.join(logDir, "runner-service.out.log"))}</string>
20556
21412
  <key>StandardErrorPath</key>
20557
- <string>${xmlEscape(path29.join(logDir, "runner-service.err.log"))}</string>
21413
+ <string>${xmlEscape(path31.join(logDir, "runner-service.err.log"))}</string>
20558
21414
  <key>ProcessType</key>
20559
21415
  <string>Background</string>
20560
21416
  </dict>
@@ -20585,12 +21441,12 @@ WantedBy=default.target
20585
21441
  `;
20586
21442
  }
20587
21443
  function launchAgentsDir() {
20588
- return path29.join(os4.homedir(), "Library", "LaunchAgents");
21444
+ return path31.join(os5.homedir(), "Library", "LaunchAgents");
20589
21445
  }
20590
21446
  function systemdUserDir() {
20591
21447
  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");
21448
+ const base = xdg ? path31.resolve(xdg) : path31.join(os5.homedir(), ".config");
21449
+ return path31.join(base, "systemd", "user");
20594
21450
  }
20595
21451
  async function runCommand(program, args) {
20596
21452
  const { stdout } = await execFileAsync(program, args);
@@ -20619,19 +21475,19 @@ var init_runner_service = __esm({
20619
21475
  kind = "launchd";
20620
21476
  identifier = LAUNCHD_LABEL;
20621
21477
  unitPath() {
20622
- return path29.join(launchAgentsDir(), `${LAUNCHD_LABEL}.plist`);
21478
+ return path31.join(launchAgentsDir(), `${LAUNCHD_LABEL}.plist`);
20623
21479
  }
20624
21480
  render(opts) {
20625
21481
  return renderLaunchdPlist({
20626
21482
  label: LAUNCHD_LABEL,
20627
21483
  invocation: opts.invocation,
20628
21484
  env: opts.env,
20629
- logDir: path29.join(resolveGlobalDataDir(), "logs")
21485
+ logDir: path31.join(resolveGlobalDataDir(), "logs")
20630
21486
  });
20631
21487
  }
20632
21488
  async install(opts) {
20633
- mkdirSync13(launchAgentsDir(), { recursive: true });
20634
- mkdirSync13(path29.join(resolveGlobalDataDir(), "logs"), { recursive: true });
21489
+ mkdirSync14(launchAgentsDir(), { recursive: true });
21490
+ mkdirSync14(path31.join(resolveGlobalDataDir(), "logs"), { recursive: true });
20635
21491
  writeServiceFile(this.unitPath(), this.render(opts));
20636
21492
  if (opts.autoStart) await this.start();
20637
21493
  }
@@ -20661,10 +21517,10 @@ var init_runner_service = __esm({
20661
21517
  await this.stop();
20662
21518
  } catch {
20663
21519
  }
20664
- if (existsSync25(this.unitPath())) rmSync6(this.unitPath());
21520
+ if (existsSync26(this.unitPath())) rmSync6(this.unitPath());
20665
21521
  }
20666
21522
  async status() {
20667
- const installed = existsSync25(this.unitPath());
21523
+ const installed = existsSync26(this.unitPath());
20668
21524
  try {
20669
21525
  const { stdout } = await runCommand("launchctl", ["list"]);
20670
21526
  const line = stdout.split("\n").find((row) => row.includes(LAUNCHD_LABEL));
@@ -20680,13 +21536,13 @@ var init_runner_service = __esm({
20680
21536
  kind = "systemd";
20681
21537
  identifier = `${SYSTEMD_UNIT_NAME}.service`;
20682
21538
  unitPath() {
20683
- return path29.join(systemdUserDir(), `${SYSTEMD_UNIT_NAME}.service`);
21539
+ return path31.join(systemdUserDir(), `${SYSTEMD_UNIT_NAME}.service`);
20684
21540
  }
20685
21541
  render(opts) {
20686
21542
  return renderSystemdUnit(opts);
20687
21543
  }
20688
21544
  async install(opts) {
20689
- mkdirSync13(systemdUserDir(), { recursive: true });
21545
+ mkdirSync14(systemdUserDir(), { recursive: true });
20690
21546
  writeServiceFile(this.unitPath(), this.render(opts));
20691
21547
  await runCommand("systemctl", ["--user", "daemon-reload"]);
20692
21548
  await runCommand("systemctl", ["--user", "enable", this.identifier]);
@@ -20707,14 +21563,14 @@ var init_runner_service = __esm({
20707
21563
  await runCommand("systemctl", ["--user", "disable", this.identifier]);
20708
21564
  } catch {
20709
21565
  }
20710
- if (existsSync25(this.unitPath())) rmSync6(this.unitPath());
21566
+ if (existsSync26(this.unitPath())) rmSync6(this.unitPath());
20711
21567
  try {
20712
21568
  await runCommand("systemctl", ["--user", "daemon-reload"]);
20713
21569
  } catch {
20714
21570
  }
20715
21571
  }
20716
21572
  async status() {
20717
- const installed = existsSync25(this.unitPath());
21573
+ const installed = existsSync26(this.unitPath());
20718
21574
  try {
20719
21575
  const { stdout } = await runCommand("systemctl", ["--user", "is-active", this.identifier]);
20720
21576
  return { installed, running: stdout.trim() === "active" ? "running" : "stopped" };
@@ -20729,9 +21585,9 @@ var init_runner_service = __esm({
20729
21585
  // src/select-prompt.ts
20730
21586
  import { createInterface as createInterface4 } from "node:readline";
20731
21587
  function parseNumberedSelection(answer, count) {
20732
- const trimmed = answer.trim();
20733
- if (!/^\d+$/.test(trimmed)) return null;
20734
- const value = Number.parseInt(trimmed, 10);
21588
+ const trimmed5 = answer.trim();
21589
+ if (!/^\d+$/.test(trimmed5)) return null;
21590
+ const value = Number.parseInt(trimmed5, 10);
20735
21591
  if (!Number.isInteger(value) || value < 1 || value > count) return null;
20736
21592
  return value - 1;
20737
21593
  }
@@ -20781,14 +21637,14 @@ var init_select_prompt = __esm({
20781
21637
 
20782
21638
  // src/session-key.ts
20783
21639
  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";
21640
+ import { existsSync as existsSync27, mkdirSync as mkdirSync15, readFileSync as readFileSync23, rmSync as rmSync7, writeFileSync as writeFileSync14 } from "node:fs";
21641
+ import path32 from "node:path";
20786
21642
  function sessionKeyCachePath({
20787
21643
  missionId,
20788
21644
  workingDirectory
20789
21645
  }) {
20790
- const key = createHash10("sha256").update(`${path30.resolve(workingDirectory)}\0${missionId}`).digest("hex");
20791
- return path30.join(resolveGlobalDataDir(), "protocol-session-keys", key);
21646
+ const key = createHash10("sha256").update(`${path32.resolve(workingDirectory)}\0${missionId}`).digest("hex");
21647
+ return path32.join(resolveGlobalDataDir(), "protocol-session-keys", key);
20792
21648
  }
20793
21649
  function readCachedSessionKey({
20794
21650
  missionId,
@@ -20796,8 +21652,8 @@ function readCachedSessionKey({
20796
21652
  }) {
20797
21653
  try {
20798
21654
  const filePath = sessionKeyCachePath({ missionId, workingDirectory });
20799
- if (!existsSync26(filePath)) return void 0;
20800
- const raw = JSON.parse(readFileSync22(filePath, "utf8"));
21655
+ if (!existsSync27(filePath)) return void 0;
21656
+ const raw = JSON.parse(readFileSync23(filePath, "utf8"));
20801
21657
  return typeof raw.sessionKey === "string" && raw.sessionKey.trim() ? raw.sessionKey.trim() : void 0;
20802
21658
  } catch {
20803
21659
  return void 0;
@@ -20809,13 +21665,13 @@ function writeCachedSessionKey({
20809
21665
  sessionKey
20810
21666
  }) {
20811
21667
  try {
20812
- const trimmed = sessionKey.trim();
20813
- if (!trimmed) return;
21668
+ const trimmed5 = sessionKey.trim();
21669
+ if (!trimmed5) return;
20814
21670
  const filePath = sessionKeyCachePath({ missionId, workingDirectory });
20815
- mkdirSync14(path30.dirname(filePath), { recursive: true });
20816
- writeFileSync13(
21671
+ mkdirSync15(path32.dirname(filePath), { recursive: true });
21672
+ writeFileSync14(
20817
21673
  filePath,
20818
- JSON.stringify({ sessionKey: trimmed, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }),
21674
+ JSON.stringify({ sessionKey: trimmed5, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }),
20819
21675
  { mode: 384 }
20820
21676
  );
20821
21677
  } catch {
@@ -20827,7 +21683,7 @@ function clearCachedSessionKey({
20827
21683
  }) {
20828
21684
  try {
20829
21685
  const filePath = sessionKeyCachePath({ missionId, workingDirectory });
20830
- if (existsSync26(filePath)) rmSync7(filePath);
21686
+ if (existsSync27(filePath)) rmSync7(filePath);
20831
21687
  } catch {
20832
21688
  }
20833
21689
  }
@@ -20845,9 +21701,9 @@ __export(commands_exports, {
20845
21701
  runManagementCommand: () => runManagementCommand,
20846
21702
  runProtocolCommand: () => runProtocolCommand
20847
21703
  });
20848
- import { existsSync as existsSync27, readFileSync as readFileSync23 } from "node:fs";
20849
- import os5 from "node:os";
20850
- import path31 from "node:path";
21704
+ import { existsSync as existsSync28, readFileSync as readFileSync24 } from "node:fs";
21705
+ import os6 from "node:os";
21706
+ import path33 from "node:path";
20851
21707
  function resourceAccessModeBody(value) {
20852
21708
  if (typeof value !== "string") return {};
20853
21709
  const normalized = value.trim().toLowerCase();
@@ -20893,7 +21749,7 @@ function readChangedFilesFromFlags(flags, stdin) {
20893
21749
  if (typeof fileFlag === "string") {
20894
21750
  const raw = fileFlag === "-" ? stdin ?? "" : (() => {
20895
21751
  try {
20896
- return readFileSync23(fileFlag, "utf8");
21752
+ return readFileSync24(fileFlag, "utf8");
20897
21753
  } catch {
20898
21754
  return "";
20899
21755
  }
@@ -20945,7 +21801,7 @@ function readJsonFlagContent({
20945
21801
  if (typeof filePath === "string") {
20946
21802
  if (fileInputs[fileFlag] !== void 0) return fileInputs[fileFlag];
20947
21803
  try {
20948
- return readFileSync23(filePath, "utf8");
21804
+ return readFileSync24(filePath, "utf8");
20949
21805
  } catch {
20950
21806
  return void 0;
20951
21807
  }
@@ -21249,7 +22105,7 @@ async function resolveProtocolFileInputs({
21249
22105
  } else if (process.stdin.isTTY) {
21250
22106
  stdinContent = "";
21251
22107
  } else {
21252
- stdinContent = readFileSync23(0, "utf8");
22108
+ stdinContent = readFileSync24(0, "utf8");
21253
22109
  }
21254
22110
  return stdinContent;
21255
22111
  };
@@ -21263,7 +22119,7 @@ async function resolveProtocolFileInputs({
21263
22119
  fileInputs[flagName] = content;
21264
22120
  stdinPayload = content;
21265
22121
  } else {
21266
- fileInputs[flagName] = readFileSync23(filePath, "utf8");
22122
+ fileInputs[flagName] = readFileSync24(filePath, "utf8");
21267
22123
  }
21268
22124
  }
21269
22125
  if (stdinPayload === void 0 && stdin !== void 0 && Object.keys(fileInputs).length === 0) {
@@ -21328,7 +22184,7 @@ async function runProtocolCommand({
21328
22184
  });
21329
22185
  if (subcommand === "record-touched") {
21330
22186
  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"));
22187
+ const rawPayload = stdin ?? (process.stdin.isTTY ? "" : readFileSync24(0, "utf8"));
21332
22188
  const result2 = recordTouchedFromPayload({
21333
22189
  rawPayload,
21334
22190
  missionOverride,
@@ -21459,9 +22315,9 @@ async function runProtocolCommand({
21459
22315
  clearCachedSessionKey({ missionId, workingDirectory });
21460
22316
  removeActiveSession({ workingDirectory, missionId });
21461
22317
  clearActiveMissionPointer(workingDirectory);
21462
- const connectorInstallsEditHook = existsSync27(path31.join(os5.homedir(), ".claude")) || existsSync27(
21463
- path31.join(
21464
- os5.homedir(),
22318
+ const connectorInstallsEditHook = existsSync28(path33.join(os6.homedir(), ".claude")) || existsSync28(
22319
+ path33.join(
22320
+ os6.homedir(),
21465
22321
  ".cursor",
21466
22322
  "plugins",
21467
22323
  "local",
@@ -21560,7 +22416,7 @@ async function runManagementCommand({
21560
22416
  case "add-cwd": {
21561
22417
  const directory = flagValue(parsed.flags, "--directory") ?? process.cwd();
21562
22418
  const existingProjectJson = readProjectJsonLink(
21563
- path31.join(directory, ".overlord", "project.json")
22419
+ path33.join(directory, ".overlord", "project.json")
21564
22420
  );
21565
22421
  const resourceKey = flagValue(parsed.flags, "--key") ?? existingProjectJson?.resourceKey;
21566
22422
  let projectId = flagValue(parsed.flags, "--project-id");
@@ -21951,13 +22807,13 @@ async function runManagementCommand({
21951
22807
  rationales: `/api/missions/${encodeURIComponent(missionId)}/file-changes`,
21952
22808
  deliveries: `/api/missions/${encodeURIComponent(missionId)}/deliveries`
21953
22809
  };
21954
- const path32 = sub ? pathBySub[sub] : void 0;
21955
- if (!path32) {
22810
+ const path34 = sub ? pathBySub[sub] : void 0;
22811
+ if (!path34) {
21956
22812
  throw new CliError({
21957
22813
  message: "Usage: ovld mission context|events|deliveries|artifacts|rationales <missionId> [--json]"
21958
22814
  });
21959
22815
  }
21960
- const result = await runtime.backend.get(path32);
22816
+ const result = await runtime.backend.get(path34);
21961
22817
  if (json || sub === "context") printJson(result);
21962
22818
  else if (Array.isArray(result)) for (const row of result) console.log(JSON.stringify(row));
21963
22819
  else printJson(result);
@@ -22127,16 +22983,33 @@ The runner will not register a target for you \u2014 declare this machine first,
22127
22983
  sessionChannelId: typeof sessionChannel.channelId === "string" ? sessionChannel.channelId : void 0,
22128
22984
  sessionChannelToken: typeof sessionChannel.token === "string" ? sessionChannel.token : void 0,
22129
22985
  sessionChannelLaunchKind: typeof sessionChannel.launchKind === "string" ? sessionChannel.launchKind : void 0,
22986
+ launchSession: launchSessionSnapshotFromMetadata(asRecord5(requestRecord.metadata)),
22130
22987
  ...terminal,
22131
22988
  dryRun
22132
22989
  }
22133
22990
  });
22991
+ if (result.providerFallbackWarning) {
22992
+ console.error(`[overlord] ${result.providerFallbackWarning}`);
22993
+ }
22994
+ if (result.viewerOpen && result.viewerOpen.ok === false) {
22995
+ console.error(`[overlord] ${result.viewerOpen.warning}`);
22996
+ }
22134
22997
  if (result.status && result.status !== 0) {
22135
22998
  throw new CliError({ message: `Launch command exited with status ${result.status}` });
22136
22999
  }
22137
- await runtime.backend.post({ path: `/api/runner/requests/${requestId}/launched` });
23000
+ await runtime.backend.post({
23001
+ path: `/api/runner/requests/${requestId}/launched`,
23002
+ body: result.providerSession ? { providerSession: result.providerSession } : {}
23003
+ });
22138
23004
  if (json || dryRun) {
22139
- printJson({ request, plan: result.plan, status: result.status });
23005
+ printJson({
23006
+ request,
23007
+ plan: result.plan,
23008
+ status: result.status,
23009
+ providerSession: result.providerSession ?? null,
23010
+ viewerOpen: result.viewerOpen ?? null,
23011
+ providerFallbackWarning: result.providerFallbackWarning ?? null
23012
+ });
22140
23013
  } else {
22141
23014
  console.log(`Launched ${requestedAgent} for ${requestRecord.missionId}`);
22142
23015
  }
@@ -22318,6 +23191,7 @@ var init_commands = __esm({
22318
23191
  init_dist2();
22319
23192
  init_project_metadata();
22320
23193
  init_local_target_mutation_runner();
23194
+ init_terminal_profile_types2();
22321
23195
  init_active_mission();
22322
23196
  init_args();
22323
23197
  init_branch_preparation();