overlord-cli 0.2607291136.0 → 0.2607292110.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
@@ -1338,8 +1338,8 @@ function normalizeBackendUrl(value) {
1338
1338
  }
1339
1339
  function isLoopbackBackendUrl(backendUrl) {
1340
1340
  try {
1341
- const hostname3 = new URL(normalizeBackendUrl(backendUrl)).hostname;
1342
- return hostname3 === "127.0.0.1" || hostname3 === "localhost" || hostname3 === "::1";
1341
+ const hostname5 = new URL(normalizeBackendUrl(backendUrl)).hostname;
1342
+ return hostname5 === "127.0.0.1" || hostname5 === "localhost" || hostname5 === "::1";
1343
1343
  } catch {
1344
1344
  return false;
1345
1345
  }
@@ -3093,12 +3093,12 @@ function createBackendClient() {
3093
3093
  const clientDevice = clientDeviceIdentity();
3094
3094
  async function request({
3095
3095
  method,
3096
- path: path28,
3096
+ path: path29,
3097
3097
  body,
3098
3098
  extraHeaders,
3099
3099
  rawBody
3100
3100
  }) {
3101
- const url = `${baseUrl}${path28.startsWith("/") ? path28 : `/${path28}`}`;
3101
+ const url = `${baseUrl}${path29.startsWith("/") ? path29 : `/${path29}`}`;
3102
3102
  const auth = resolveAuthHeaders({ baseUrl });
3103
3103
  let response;
3104
3104
  try {
@@ -3125,14 +3125,14 @@ Start the Desktop/local backend or run \`ovld config set cloud <url>\`.
3125
3125
  const payload = await readResponseJson2(response);
3126
3126
  if (!response.ok) {
3127
3127
  if (response.status === 401 && auth.headers.Authorization) {
3128
- const detail = errorMessageFromJson2(payload) ?? `Backend request failed: ${method} ${path28} (${response.status})`;
3128
+ const detail = errorMessageFromJson2(payload) ?? `Backend request failed: ${method} ${path29} (${response.status})`;
3129
3129
  throw new CliError({
3130
3130
  message: `${detail}
3131
3131
  ` + (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.")
3132
3132
  });
3133
3133
  }
3134
3134
  throw new CliError({
3135
- message: errorMessageFromJson2(payload) ?? `Backend request failed: ${method} ${path28} (${response.status})`
3135
+ message: errorMessageFromJson2(payload) ?? `Backend request failed: ${method} ${path29} (${response.status})`
3136
3136
  });
3137
3137
  }
3138
3138
  return payload;
@@ -3140,13 +3140,13 @@ Start the Desktop/local backend or run \`ovld config set cloud <url>\`.
3140
3140
  return {
3141
3141
  baseUrl,
3142
3142
  health: () => request({ method: "GET", path: "/api/health" }),
3143
- get: (path28) => request({ method: "GET", path: path28 }),
3144
- post: ({ path: path28, body }) => request({ method: "POST", path: path28, body }),
3145
- patch: ({ path: path28, body }) => request({ method: "PATCH", path: path28, body }),
3146
- delete: (path28) => request({ method: "DELETE", path: path28 }),
3147
- postRaw: ({ path: path28, body, contentType, filename }) => request({
3143
+ get: (path29) => request({ method: "GET", path: path29 }),
3144
+ post: ({ path: path29, body }) => request({ method: "POST", path: path29, body }),
3145
+ patch: ({ path: path29, body }) => request({ method: "PATCH", path: path29, body }),
3146
+ delete: (path29) => request({ method: "DELETE", path: path29 }),
3147
+ postRaw: ({ path: path29, body, contentType, filename }) => request({
3148
3148
  method: "POST",
3149
- path: path28,
3149
+ path: path29,
3150
3150
  rawBody: body,
3151
3151
  extraHeaders: {
3152
3152
  "Content-Type": contentType || "application/octet-stream",
@@ -3349,6 +3349,7 @@ __export(setup_exports, {
3349
3349
  runAgentSetupCommand: () => runAgentSetupCommand,
3350
3350
  runSetupCommand: () => runSetupCommand
3351
3351
  });
3352
+ import { hostname as hostname3 } from "node:os";
3352
3353
  function printHumanResult(result) {
3353
3354
  const verb = result.dryRun ? "Would install" : "Installed";
3354
3355
  printLine(`${verb} connector "${result.agentKey}" \u2192 ${result.installPath}`);
@@ -3363,6 +3364,9 @@ function printHumanResult(result) {
3363
3364
  function isHttpUrl(value) {
3364
3365
  return /^https?:\/\//i.test(value.trim());
3365
3366
  }
3367
+ function asRecord(value) {
3368
+ return value && typeof value === "object" ? value : {};
3369
+ }
3366
3370
  function shellQuote(value) {
3367
3371
  return `'${value.replace(/'/g, `'\\''`)}'`;
3368
3372
  }
@@ -3614,10 +3618,55 @@ async function resolveCurrentTerminalProfile({
3614
3618
  };
3615
3619
  }
3616
3620
  }
3621
+ async function configureExecutionTargetForSetup({
3622
+ runtime
3623
+ }) {
3624
+ printLine("");
3625
+ printStepTitle("Step 4: Register this machine as an execution target.");
3626
+ printLine(" Agents can only be launched on machines you have registered.");
3627
+ if (!await promptYesNo("Register this machine", true)) {
3628
+ printLine(' Skipped. Register it later with `ovld add-et --name "<name>"`.');
3629
+ return { registered: false, reason: "declined" };
3630
+ }
3631
+ const name = await promptLine2({ message: "Target name", defaultValue: hostname3() });
3632
+ let result;
3633
+ try {
3634
+ result = asRecord(
3635
+ await runtime.backend.post({
3636
+ path: "/api/protocol/register-target",
3637
+ body: {
3638
+ args: [],
3639
+ positional: [],
3640
+ flags: name ? { "--name": name } : {},
3641
+ fileInputs: {}
3642
+ }
3643
+ })
3644
+ );
3645
+ } catch (error) {
3646
+ printLine(` Could not register: ${error instanceof Error ? error.message : String(error)}`);
3647
+ printLine(' Retry later with `ovld add-et --name "<name>"`.');
3648
+ return { registered: false, reason: "failed" };
3649
+ }
3650
+ if (result.status === "workspace_selection_required") {
3651
+ const workspaces = Array.isArray(result.workspaces) ? result.workspaces : [];
3652
+ printLine(" You belong to more than one workspace, so this needs an explicit choice:");
3653
+ for (const entry of workspaces) {
3654
+ const ws = asRecord(entry);
3655
+ printLine(` - ${String(ws.name ?? ws.id)} (${String(ws.slug ?? ws.id)})`);
3656
+ }
3657
+ printLine(' Run `ovld add-et --name "<name>" --workspace-id <id>` to finish.');
3658
+ return { registered: false, reason: "workspace_selection_required" };
3659
+ }
3660
+ const target = asRecord(result.executionTarget);
3661
+ const executionTargetId = String(target.executionTargetId ?? "");
3662
+ const label = String(target.label ?? name);
3663
+ printLine(` Registered execution target ${label} (${executionTargetId}).`);
3664
+ return { registered: true, executionTargetId, label };
3665
+ }
3617
3666
  async function configureTerminalForSetup({ runtime }) {
3618
3667
  const current = await resolveCurrentTerminalProfile({ runtime });
3619
3668
  printLine("");
3620
- printStepTitle("Step 4: Choose the default terminal for launched agents.");
3669
+ printStepTitle("Step 5: Choose the default terminal for launched agents.");
3621
3670
  TERMINAL_OPTIONS.forEach((option, index) => {
3622
3671
  printLine(` ${index + 1}. ${option.label}`);
3623
3672
  });
@@ -3686,7 +3735,14 @@ async function runFullSetupCommand({ json }) {
3686
3735
  const agents = await configureAgentsForSetup();
3687
3736
  const runtime = openCliRuntime();
3688
3737
  try {
3689
- const terminal = await configureTerminalForSetup({ runtime });
3738
+ const executionTarget = await configureExecutionTargetForSetup({ runtime });
3739
+ const terminal = executionTarget.registered ? await configureTerminalForSetup({ runtime }) : null;
3740
+ if (!terminal) {
3741
+ printLine("");
3742
+ printLine(
3743
+ 'Skipping the terminal step: launch settings are stored per execution target, so register this machine first with `ovld add-et --name "<name>"`.'
3744
+ );
3745
+ }
3690
3746
  if (json) {
3691
3747
  printJson({
3692
3748
  ok: true,
@@ -3698,6 +3754,7 @@ async function runFullSetupCommand({ json }) {
3698
3754
  credentialsPath: auth.credentialsPath
3699
3755
  },
3700
3756
  agents: agents.map((result) => result.agentKey),
3757
+ executionTarget,
3701
3758
  terminal
3702
3759
  });
3703
3760
  } else {
@@ -4748,17 +4805,17 @@ var require_visit = __commonJS({
4748
4805
  visit.BREAK = BREAK;
4749
4806
  visit.SKIP = SKIP;
4750
4807
  visit.REMOVE = REMOVE;
4751
- function visit_(key, node, visitor, path28) {
4752
- const ctrl = callVisitor(key, node, visitor, path28);
4808
+ function visit_(key, node, visitor, path29) {
4809
+ const ctrl = callVisitor(key, node, visitor, path29);
4753
4810
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
4754
- replaceNode(key, path28, ctrl);
4755
- return visit_(key, ctrl, visitor, path28);
4811
+ replaceNode(key, path29, ctrl);
4812
+ return visit_(key, ctrl, visitor, path29);
4756
4813
  }
4757
4814
  if (typeof ctrl !== "symbol") {
4758
4815
  if (identity.isCollection(node)) {
4759
- path28 = Object.freeze(path28.concat(node));
4816
+ path29 = Object.freeze(path29.concat(node));
4760
4817
  for (let i = 0; i < node.items.length; ++i) {
4761
- const ci = visit_(i, node.items[i], visitor, path28);
4818
+ const ci = visit_(i, node.items[i], visitor, path29);
4762
4819
  if (typeof ci === "number")
4763
4820
  i = ci - 1;
4764
4821
  else if (ci === BREAK)
@@ -4769,13 +4826,13 @@ var require_visit = __commonJS({
4769
4826
  }
4770
4827
  }
4771
4828
  } else if (identity.isPair(node)) {
4772
- path28 = Object.freeze(path28.concat(node));
4773
- const ck = visit_("key", node.key, visitor, path28);
4829
+ path29 = Object.freeze(path29.concat(node));
4830
+ const ck = visit_("key", node.key, visitor, path29);
4774
4831
  if (ck === BREAK)
4775
4832
  return BREAK;
4776
4833
  else if (ck === REMOVE)
4777
4834
  node.key = null;
4778
- const cv = visit_("value", node.value, visitor, path28);
4835
+ const cv = visit_("value", node.value, visitor, path29);
4779
4836
  if (cv === BREAK)
4780
4837
  return BREAK;
4781
4838
  else if (cv === REMOVE)
@@ -4796,17 +4853,17 @@ var require_visit = __commonJS({
4796
4853
  visitAsync.BREAK = BREAK;
4797
4854
  visitAsync.SKIP = SKIP;
4798
4855
  visitAsync.REMOVE = REMOVE;
4799
- async function visitAsync_(key, node, visitor, path28) {
4800
- const ctrl = await callVisitor(key, node, visitor, path28);
4856
+ async function visitAsync_(key, node, visitor, path29) {
4857
+ const ctrl = await callVisitor(key, node, visitor, path29);
4801
4858
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
4802
- replaceNode(key, path28, ctrl);
4803
- return visitAsync_(key, ctrl, visitor, path28);
4859
+ replaceNode(key, path29, ctrl);
4860
+ return visitAsync_(key, ctrl, visitor, path29);
4804
4861
  }
4805
4862
  if (typeof ctrl !== "symbol") {
4806
4863
  if (identity.isCollection(node)) {
4807
- path28 = Object.freeze(path28.concat(node));
4864
+ path29 = Object.freeze(path29.concat(node));
4808
4865
  for (let i = 0; i < node.items.length; ++i) {
4809
- const ci = await visitAsync_(i, node.items[i], visitor, path28);
4866
+ const ci = await visitAsync_(i, node.items[i], visitor, path29);
4810
4867
  if (typeof ci === "number")
4811
4868
  i = ci - 1;
4812
4869
  else if (ci === BREAK)
@@ -4817,13 +4874,13 @@ var require_visit = __commonJS({
4817
4874
  }
4818
4875
  }
4819
4876
  } else if (identity.isPair(node)) {
4820
- path28 = Object.freeze(path28.concat(node));
4821
- const ck = await visitAsync_("key", node.key, visitor, path28);
4877
+ path29 = Object.freeze(path29.concat(node));
4878
+ const ck = await visitAsync_("key", node.key, visitor, path29);
4822
4879
  if (ck === BREAK)
4823
4880
  return BREAK;
4824
4881
  else if (ck === REMOVE)
4825
4882
  node.key = null;
4826
- const cv = await visitAsync_("value", node.value, visitor, path28);
4883
+ const cv = await visitAsync_("value", node.value, visitor, path29);
4827
4884
  if (cv === BREAK)
4828
4885
  return BREAK;
4829
4886
  else if (cv === REMOVE)
@@ -4850,23 +4907,23 @@ var require_visit = __commonJS({
4850
4907
  }
4851
4908
  return visitor;
4852
4909
  }
4853
- function callVisitor(key, node, visitor, path28) {
4910
+ function callVisitor(key, node, visitor, path29) {
4854
4911
  if (typeof visitor === "function")
4855
- return visitor(key, node, path28);
4912
+ return visitor(key, node, path29);
4856
4913
  if (identity.isMap(node))
4857
- return visitor.Map?.(key, node, path28);
4914
+ return visitor.Map?.(key, node, path29);
4858
4915
  if (identity.isSeq(node))
4859
- return visitor.Seq?.(key, node, path28);
4916
+ return visitor.Seq?.(key, node, path29);
4860
4917
  if (identity.isPair(node))
4861
- return visitor.Pair?.(key, node, path28);
4918
+ return visitor.Pair?.(key, node, path29);
4862
4919
  if (identity.isScalar(node))
4863
- return visitor.Scalar?.(key, node, path28);
4920
+ return visitor.Scalar?.(key, node, path29);
4864
4921
  if (identity.isAlias(node))
4865
- return visitor.Alias?.(key, node, path28);
4922
+ return visitor.Alias?.(key, node, path29);
4866
4923
  return void 0;
4867
4924
  }
4868
- function replaceNode(key, path28, node) {
4869
- const parent = path28[path28.length - 1];
4925
+ function replaceNode(key, path29, node) {
4926
+ const parent = path29[path29.length - 1];
4870
4927
  if (identity.isCollection(parent)) {
4871
4928
  parent.items[key] = node;
4872
4929
  } else if (identity.isPair(parent)) {
@@ -5476,10 +5533,10 @@ var require_Collection = __commonJS({
5476
5533
  var createNode = require_createNode();
5477
5534
  var identity = require_identity();
5478
5535
  var Node = require_Node();
5479
- function collectionFromPath(schema, path28, value) {
5536
+ function collectionFromPath(schema, path29, value) {
5480
5537
  let v = value;
5481
- for (let i = path28.length - 1; i >= 0; --i) {
5482
- const k = path28[i];
5538
+ for (let i = path29.length - 1; i >= 0; --i) {
5539
+ const k = path29[i];
5483
5540
  if (typeof k === "number" && Number.isInteger(k) && k >= 0) {
5484
5541
  const a = [];
5485
5542
  a[k] = v;
@@ -5498,7 +5555,7 @@ var require_Collection = __commonJS({
5498
5555
  sourceObjects: /* @__PURE__ */ new Map()
5499
5556
  });
5500
5557
  }
5501
- var isEmptyPath = (path28) => path28 == null || typeof path28 === "object" && !!path28[Symbol.iterator]().next().done;
5558
+ var isEmptyPath = (path29) => path29 == null || typeof path29 === "object" && !!path29[Symbol.iterator]().next().done;
5502
5559
  var Collection = class extends Node.NodeBase {
5503
5560
  constructor(type, schema) {
5504
5561
  super(type);
@@ -5528,11 +5585,11 @@ var require_Collection = __commonJS({
5528
5585
  * be a Pair instance or a `{ key, value }` object, which may not have a key
5529
5586
  * that already exists in the map.
5530
5587
  */
5531
- addIn(path28, value) {
5532
- if (isEmptyPath(path28))
5588
+ addIn(path29, value) {
5589
+ if (isEmptyPath(path29))
5533
5590
  this.add(value);
5534
5591
  else {
5535
- const [key, ...rest] = path28;
5592
+ const [key, ...rest] = path29;
5536
5593
  const node = this.get(key, true);
5537
5594
  if (identity.isCollection(node))
5538
5595
  node.addIn(rest, value);
@@ -5546,8 +5603,8 @@ var require_Collection = __commonJS({
5546
5603
  * Removes a value from the collection.
5547
5604
  * @returns `true` if the item was found and removed.
5548
5605
  */
5549
- deleteIn(path28) {
5550
- const [key, ...rest] = path28;
5606
+ deleteIn(path29) {
5607
+ const [key, ...rest] = path29;
5551
5608
  if (rest.length === 0)
5552
5609
  return this.delete(key);
5553
5610
  const node = this.get(key, true);
@@ -5561,8 +5618,8 @@ var require_Collection = __commonJS({
5561
5618
  * scalar values from their surrounding node; to disable set `keepScalar` to
5562
5619
  * `true` (collections are always returned intact).
5563
5620
  */
5564
- getIn(path28, keepScalar) {
5565
- const [key, ...rest] = path28;
5621
+ getIn(path29, keepScalar) {
5622
+ const [key, ...rest] = path29;
5566
5623
  const node = this.get(key, true);
5567
5624
  if (rest.length === 0)
5568
5625
  return !keepScalar && identity.isScalar(node) ? node.value : node;
@@ -5580,8 +5637,8 @@ var require_Collection = __commonJS({
5580
5637
  /**
5581
5638
  * Checks if the collection includes a value with the key `key`.
5582
5639
  */
5583
- hasIn(path28) {
5584
- const [key, ...rest] = path28;
5640
+ hasIn(path29) {
5641
+ const [key, ...rest] = path29;
5585
5642
  if (rest.length === 0)
5586
5643
  return this.has(key);
5587
5644
  const node = this.get(key, true);
@@ -5591,8 +5648,8 @@ var require_Collection = __commonJS({
5591
5648
  * Sets a value in this collection. For `!!set`, `value` needs to be a
5592
5649
  * boolean to add/remove the item from the set.
5593
5650
  */
5594
- setIn(path28, value) {
5595
- const [key, ...rest] = path28;
5651
+ setIn(path29, value) {
5652
+ const [key, ...rest] = path29;
5596
5653
  if (rest.length === 0) {
5597
5654
  this.set(key, value);
5598
5655
  } else {
@@ -8107,9 +8164,9 @@ var require_Document = __commonJS({
8107
8164
  this.contents.add(value);
8108
8165
  }
8109
8166
  /** Adds a value to the document. */
8110
- addIn(path28, value) {
8167
+ addIn(path29, value) {
8111
8168
  if (assertCollection(this.contents))
8112
- this.contents.addIn(path28, value);
8169
+ this.contents.addIn(path29, value);
8113
8170
  }
8114
8171
  /**
8115
8172
  * Create a new `Alias` node, ensuring that the target `node` has the required anchor.
@@ -8184,14 +8241,14 @@ var require_Document = __commonJS({
8184
8241
  * Removes a value from the document.
8185
8242
  * @returns `true` if the item was found and removed.
8186
8243
  */
8187
- deleteIn(path28) {
8188
- if (Collection.isEmptyPath(path28)) {
8244
+ deleteIn(path29) {
8245
+ if (Collection.isEmptyPath(path29)) {
8189
8246
  if (this.contents == null)
8190
8247
  return false;
8191
8248
  this.contents = null;
8192
8249
  return true;
8193
8250
  }
8194
- return assertCollection(this.contents) ? this.contents.deleteIn(path28) : false;
8251
+ return assertCollection(this.contents) ? this.contents.deleteIn(path29) : false;
8195
8252
  }
8196
8253
  /**
8197
8254
  * Returns item at `key`, or `undefined` if not found. By default unwraps
@@ -8206,10 +8263,10 @@ var require_Document = __commonJS({
8206
8263
  * scalar values from their surrounding node; to disable set `keepScalar` to
8207
8264
  * `true` (collections are always returned intact).
8208
8265
  */
8209
- getIn(path28, keepScalar) {
8210
- if (Collection.isEmptyPath(path28))
8266
+ getIn(path29, keepScalar) {
8267
+ if (Collection.isEmptyPath(path29))
8211
8268
  return !keepScalar && identity.isScalar(this.contents) ? this.contents.value : this.contents;
8212
- return identity.isCollection(this.contents) ? this.contents.getIn(path28, keepScalar) : void 0;
8269
+ return identity.isCollection(this.contents) ? this.contents.getIn(path29, keepScalar) : void 0;
8213
8270
  }
8214
8271
  /**
8215
8272
  * Checks if the document includes a value with the key `key`.
@@ -8220,10 +8277,10 @@ var require_Document = __commonJS({
8220
8277
  /**
8221
8278
  * Checks if the document includes a value at `path`.
8222
8279
  */
8223
- hasIn(path28) {
8224
- if (Collection.isEmptyPath(path28))
8280
+ hasIn(path29) {
8281
+ if (Collection.isEmptyPath(path29))
8225
8282
  return this.contents !== void 0;
8226
- return identity.isCollection(this.contents) ? this.contents.hasIn(path28) : false;
8283
+ return identity.isCollection(this.contents) ? this.contents.hasIn(path29) : false;
8227
8284
  }
8228
8285
  /**
8229
8286
  * Sets a value in this document. For `!!set`, `value` needs to be a
@@ -8240,13 +8297,13 @@ var require_Document = __commonJS({
8240
8297
  * Sets a value in this document. For `!!set`, `value` needs to be a
8241
8298
  * boolean to add/remove the item from the set.
8242
8299
  */
8243
- setIn(path28, value) {
8244
- if (Collection.isEmptyPath(path28)) {
8300
+ setIn(path29, value) {
8301
+ if (Collection.isEmptyPath(path29)) {
8245
8302
  this.contents = value;
8246
8303
  } else if (this.contents == null) {
8247
- this.contents = Collection.collectionFromPath(this.schema, Array.from(path28), value);
8304
+ this.contents = Collection.collectionFromPath(this.schema, Array.from(path29), value);
8248
8305
  } else if (assertCollection(this.contents)) {
8249
- this.contents.setIn(path28, value);
8306
+ this.contents.setIn(path29, value);
8250
8307
  }
8251
8308
  }
8252
8309
  /**
@@ -10206,9 +10263,9 @@ var require_cst_visit = __commonJS({
10206
10263
  visit.BREAK = BREAK;
10207
10264
  visit.SKIP = SKIP;
10208
10265
  visit.REMOVE = REMOVE;
10209
- visit.itemAtPath = (cst, path28) => {
10266
+ visit.itemAtPath = (cst, path29) => {
10210
10267
  let item = cst;
10211
- for (const [field, index] of path28) {
10268
+ for (const [field, index] of path29) {
10212
10269
  const tok = item?.[field];
10213
10270
  if (tok && "items" in tok) {
10214
10271
  item = tok.items[index];
@@ -10217,23 +10274,23 @@ var require_cst_visit = __commonJS({
10217
10274
  }
10218
10275
  return item;
10219
10276
  };
10220
- visit.parentCollection = (cst, path28) => {
10221
- const parent = visit.itemAtPath(cst, path28.slice(0, -1));
10222
- const field = path28[path28.length - 1][0];
10277
+ visit.parentCollection = (cst, path29) => {
10278
+ const parent = visit.itemAtPath(cst, path29.slice(0, -1));
10279
+ const field = path29[path29.length - 1][0];
10223
10280
  const coll = parent?.[field];
10224
10281
  if (coll && "items" in coll)
10225
10282
  return coll;
10226
10283
  throw new Error("Parent collection not found");
10227
10284
  };
10228
- function _visit(path28, item, visitor) {
10229
- let ctrl = visitor(item, path28);
10285
+ function _visit(path29, item, visitor) {
10286
+ let ctrl = visitor(item, path29);
10230
10287
  if (typeof ctrl === "symbol")
10231
10288
  return ctrl;
10232
10289
  for (const field of ["key", "value"]) {
10233
10290
  const token = item[field];
10234
10291
  if (token && "items" in token) {
10235
10292
  for (let i = 0; i < token.items.length; ++i) {
10236
- const ci = _visit(Object.freeze(path28.concat([[field, i]])), token.items[i], visitor);
10293
+ const ci = _visit(Object.freeze(path29.concat([[field, i]])), token.items[i], visitor);
10237
10294
  if (typeof ci === "number")
10238
10295
  i = ci - 1;
10239
10296
  else if (ci === BREAK)
@@ -10244,10 +10301,10 @@ var require_cst_visit = __commonJS({
10244
10301
  }
10245
10302
  }
10246
10303
  if (typeof ctrl === "function" && field === "key")
10247
- ctrl = ctrl(item, path28);
10304
+ ctrl = ctrl(item, path29);
10248
10305
  }
10249
10306
  }
10250
- return typeof ctrl === "function" ? ctrl(item, path28) : ctrl;
10307
+ return typeof ctrl === "function" ? ctrl(item, path29) : ctrl;
10251
10308
  }
10252
10309
  exports.visit = visit;
10253
10310
  }
@@ -12323,8 +12380,8 @@ function accessModeToResourcePathPermission({ accessMode, isPrimary = false }) {
12323
12380
  return "rw";
12324
12381
  return accessMode === "read" ? "ro" : "rw";
12325
12382
  }
12326
- function formatResourcePathWithPermission({ path: path28, accessMode, isPrimary = false }) {
12327
- const trimmed = path28.trim();
12383
+ function formatResourcePathWithPermission({ path: path29, accessMode, isPrimary = false }) {
12384
+ const trimmed = path29.trim();
12328
12385
  if (!trimmed)
12329
12386
  return "";
12330
12387
  const permission = accessModeToResourcePathPermission({ accessMode, isPrimary });
@@ -12338,11 +12395,11 @@ function formatProjectResourcePathsFromManifest(projectResources) {
12338
12395
  if (!entry || typeof entry !== "object")
12339
12396
  continue;
12340
12397
  const record = entry;
12341
- const path28 = typeof record.path === "string" ? record.path.trim() : "";
12342
- if (!path28)
12398
+ const path29 = typeof record.path === "string" ? record.path.trim() : "";
12399
+ if (!path29)
12343
12400
  continue;
12344
12401
  paths.push(formatResourcePathWithPermission({
12345
- path: path28,
12402
+ path: path29,
12346
12403
  accessMode: typeof record.accessMode === "string" ? record.accessMode : null,
12347
12404
  isPrimary: record.isPrimary === true
12348
12405
  }));
@@ -13891,10 +13948,10 @@ function primaryResourcePath(projectResources) {
13891
13948
  for (const entry of projectResources) {
13892
13949
  if (!entry || typeof entry !== "object") continue;
13893
13950
  const record = entry;
13894
- const path28 = typeof record.path === "string" ? record.path.trim() : "";
13895
- if (!path28) continue;
13896
- if (record.isPrimary === true) return path28;
13897
- if (record.isCurrent === true && !currentPath) currentPath = path28;
13951
+ const path29 = typeof record.path === "string" ? record.path.trim() : "";
13952
+ if (!path29) continue;
13953
+ if (record.isPrimary === true) return path29;
13954
+ if (record.isCurrent === true && !currentPath) currentPath = path29;
13898
13955
  }
13899
13956
  return currentPath;
13900
13957
  }
@@ -14332,21 +14389,21 @@ function overlordLaunchEnv({
14332
14389
  ...projectResources && projectResources.length > 0 ? { OVERLORD_PROJECT_RESOURCES: JSON.stringify(projectResources) } : {}
14333
14390
  };
14334
14391
  }
14335
- function asRecord(value) {
14392
+ function asRecord2(value) {
14336
14393
  return value && typeof value === "object" ? value : {};
14337
14394
  }
14338
14395
  async function loadMissionContext({
14339
14396
  runtime,
14340
14397
  missionId
14341
14398
  }) {
14342
- const mission = asRecord(
14399
+ const mission = asRecord2(
14343
14400
  await runtime.backend.get(`/api/missions/${encodeURIComponent(missionId)}`)
14344
14401
  );
14345
14402
  const events = await runtime.backend.get(`/api/missions/${encodeURIComponent(missionId)}/events`).catch(() => []);
14346
14403
  const artifacts = await runtime.backend.get(`/api/missions/${encodeURIComponent(missionId)}/artifacts`).catch(() => []);
14347
14404
  const displayId = String(mission.displayId ?? mission.id ?? missionId);
14348
14405
  const title = String(mission.title ?? "(untitled)");
14349
- const objectives = Array.isArray(mission.objectives) ? mission.objectives.map(asRecord) : [];
14406
+ const objectives = Array.isArray(mission.objectives) ? mission.objectives.map(asRecord2) : [];
14350
14407
  const attachmentLines = [];
14351
14408
  await Promise.all(
14352
14409
  objectives.map(async (objective, index) => {
@@ -14354,7 +14411,7 @@ async function loadMissionContext({
14354
14411
  if (typeof objectiveId !== "string" || objectiveId.length === 0) return;
14355
14412
  const attachments = await runtime.backend.get(`/api/objectives/${encodeURIComponent(objectiveId)}/attachments`).catch(() => []);
14356
14413
  for (const attachment of attachments) {
14357
- const record = asRecord(attachment);
14414
+ const record = asRecord2(attachment);
14358
14415
  const filename = String(record.filename ?? "attachment");
14359
14416
  const contentType = record.contentType ? ` (${String(record.contentType)})` : "";
14360
14417
  attachmentLines.push(`- [objective ${index + 1}] ${filename}${contentType}`);
@@ -14381,11 +14438,11 @@ async function loadMissionContext({
14381
14438
  ""
14382
14439
  ] : [],
14383
14440
  "## Recent Activity",
14384
- ...events.filter((event) => !AGENT_HISTORY_EXCLUDED_EVENT_TYPES.has(String(asRecord(event).type))).slice(-20).map((event) => `- ${asRecord(event).summary ?? JSON.stringify(event)}`),
14441
+ ...events.filter((event) => !AGENT_HISTORY_EXCLUDED_EVENT_TYPES.has(String(asRecord2(event).type))).slice(-20).map((event) => `- ${asRecord2(event).summary ?? JSON.stringify(event)}`),
14385
14442
  "",
14386
14443
  "## Artifacts",
14387
14444
  ...artifacts.map(
14388
- (artifact) => `- ${asRecord(artifact).label ?? asRecord(artifact).type ?? "artifact"}`
14445
+ (artifact) => `- ${asRecord2(artifact).label ?? asRecord2(artifact).type ?? "artifact"}`
14389
14446
  ),
14390
14447
  "",
14391
14448
  "Use `ovld protocol attach --mission-id <id>` before making changes, update during work, and ALWAYS deliver last."
@@ -14407,7 +14464,7 @@ async function loadProjectResourcesForLaunch({
14407
14464
  }
14408
14465
  }
14409
14466
  });
14410
- const record = asRecord(context);
14467
+ const record = asRecord2(context);
14411
14468
  return Array.isArray(record.projectResources) ? record.projectResources : null;
14412
14469
  } catch {
14413
14470
  return null;
@@ -16174,14 +16231,82 @@ var init_resource_observations = __esm({
16174
16231
  }
16175
16232
  });
16176
16233
 
16234
+ // src/runner-identity.ts
16235
+ import { randomUUID } from "node:crypto";
16236
+ import { existsSync as existsSync21, mkdirSync as mkdirSync10, readFileSync as readFileSync16, writeFileSync as writeFileSync9 } from "node:fs";
16237
+ import { hostname as hostname4 } from "node:os";
16238
+ import path25 from "node:path";
16239
+ function envValue(name) {
16240
+ const value = process.env[name]?.trim();
16241
+ return value && value.length > 0 ? value : null;
16242
+ }
16243
+ function runnerInstanceStatePath(dataDir = resolveGlobalDataDir()) {
16244
+ return path25.join(dataDir, RUNNER_INSTANCE_STATE_FILENAME);
16245
+ }
16246
+ function resolveRunnerInstanceId(dataDir = resolveGlobalDataDir()) {
16247
+ const pinned = envValue("OVERLORD_RUNNER_INSTANCE_ID");
16248
+ if (pinned) return pinned;
16249
+ const statePath = runnerInstanceStatePath(dataDir);
16250
+ if (existsSync21(statePath)) {
16251
+ try {
16252
+ const parsed = JSON.parse(readFileSync16(statePath, "utf8"));
16253
+ if (typeof parsed.runnerInstanceId === "string" && parsed.runnerInstanceId.trim()) {
16254
+ return parsed.runnerInstanceId.trim();
16255
+ }
16256
+ } catch {
16257
+ }
16258
+ }
16259
+ const runnerInstanceId = randomUUID();
16260
+ try {
16261
+ mkdirSync10(path25.dirname(statePath), { recursive: true });
16262
+ writeFileSync9(statePath, `${JSON.stringify({ runnerInstanceId }, null, 2)}
16263
+ `, { mode: 384 });
16264
+ } catch {
16265
+ }
16266
+ return runnerInstanceId;
16267
+ }
16268
+ function runnerRegistrationPayload(dataDir = resolveGlobalDataDir()) {
16269
+ const executionTargetId = envValue("OVERLORD_EXECUTION_TARGET_ID");
16270
+ const relationEnv = envValue("OVERLORD_RUNNER_RELATION");
16271
+ if (relationEnv && relationEnv !== "native" && relationEnv !== "adopted") {
16272
+ throw new CliError({
16273
+ message: `OVERLORD_RUNNER_RELATION must be "native" or "adopted" (got "${relationEnv}").`
16274
+ });
16275
+ }
16276
+ if (relationEnv === "adopted" && !executionTargetId) {
16277
+ throw new CliError({
16278
+ message: "OVERLORD_RUNNER_RELATION=adopted requires OVERLORD_EXECUTION_TARGET_ID naming the host execution target this runner adopts."
16279
+ });
16280
+ }
16281
+ return {
16282
+ ...executionTargetId ? { executionTargetId } : {},
16283
+ runnerInstanceId: resolveRunnerInstanceId(dataDir),
16284
+ // Left unset unless declared: the backend knows whether the named target is
16285
+ // this machine's own and derives native/adopted from that.
16286
+ ...relationEnv ? { runnerRelation: relationEnv } : {},
16287
+ runnerLabel: envValue("OVERLORD_DEVICE_LABEL") ?? hostname4(),
16288
+ runnerVersion: getCliVersion()
16289
+ };
16290
+ }
16291
+ var RUNNER_INSTANCE_STATE_FILENAME;
16292
+ var init_runner_identity = __esm({
16293
+ "src/runner-identity.ts"() {
16294
+ "use strict";
16295
+ init_config();
16296
+ init_errors();
16297
+ init_version();
16298
+ RUNNER_INSTANCE_STATE_FILENAME = "runner-instance.json";
16299
+ }
16300
+ });
16301
+
16177
16302
  // src/runner-service.ts
16178
16303
  import { execFile } from "node:child_process";
16179
- import { chmodSync as chmodSync4, existsSync as existsSync21, mkdirSync as mkdirSync10, readFileSync as readFileSync16, rmSync as rmSync5, writeFileSync as writeFileSync9 } from "node:fs";
16304
+ import { chmodSync as chmodSync4, existsSync as existsSync22, mkdirSync as mkdirSync11, readFileSync as readFileSync17, rmSync as rmSync5, writeFileSync as writeFileSync10 } from "node:fs";
16180
16305
  import os4 from "node:os";
16181
- import path25 from "node:path";
16306
+ import path26 from "node:path";
16182
16307
  import { promisify } from "node:util";
16183
16308
  function writeServiceFile(filePath, contents) {
16184
- writeFileSync9(filePath, contents, { mode: 384 });
16309
+ writeFileSync10(filePath, contents, { mode: 384 });
16185
16310
  chmodSync4(filePath, 384);
16186
16311
  }
16187
16312
  function emptyRunnerServiceState() {
@@ -16200,21 +16325,21 @@ function emptyRunnerServiceState() {
16200
16325
  };
16201
16326
  }
16202
16327
  function runnerServiceStatePath(dataDir = resolveGlobalDataDir()) {
16203
- return path25.join(dataDir, RUNNER_SERVICE_STATE_FILENAME);
16328
+ return path26.join(dataDir, RUNNER_SERVICE_STATE_FILENAME);
16204
16329
  }
16205
16330
  function readRunnerServiceState(dataDir = resolveGlobalDataDir()) {
16206
16331
  const filePath = runnerServiceStatePath(dataDir);
16207
- if (!existsSync21(filePath)) return emptyRunnerServiceState();
16332
+ if (!existsSync22(filePath)) return emptyRunnerServiceState();
16208
16333
  try {
16209
- const parsed = JSON.parse(readFileSync16(filePath, "utf8"));
16334
+ const parsed = JSON.parse(readFileSync17(filePath, "utf8"));
16210
16335
  return { ...emptyRunnerServiceState(), ...parsed };
16211
16336
  } catch {
16212
16337
  return emptyRunnerServiceState();
16213
16338
  }
16214
16339
  }
16215
16340
  function writeRunnerServiceState(state, dataDir = resolveGlobalDataDir()) {
16216
- mkdirSync10(dataDir, { recursive: true });
16217
- writeFileSync9(runnerServiceStatePath(dataDir), `${JSON.stringify(state, null, 2)}
16341
+ mkdirSync11(dataDir, { recursive: true });
16342
+ writeFileSync10(runnerServiceStatePath(dataDir), `${JSON.stringify(state, null, 2)}
16218
16343
  `, "utf8");
16219
16344
  }
16220
16345
  function patchRunnerServiceState(patch, dataDir = resolveGlobalDataDir()) {
@@ -16223,13 +16348,13 @@ function patchRunnerServiceState(patch, dataDir = resolveGlobalDataDir()) {
16223
16348
  return next;
16224
16349
  }
16225
16350
  function runnerFocusStatePath(dataDir = resolveGlobalDataDir()) {
16226
- return path25.join(dataDir, RUNNER_FOCUS_STATE_FILENAME);
16351
+ return path26.join(dataDir, RUNNER_FOCUS_STATE_FILENAME);
16227
16352
  }
16228
16353
  function readDesktopFocusState(dataDir = resolveGlobalDataDir()) {
16229
16354
  const filePath = runnerFocusStatePath(dataDir);
16230
- if (!existsSync21(filePath)) return { lastFocusedAt: null };
16355
+ if (!existsSync22(filePath)) return { lastFocusedAt: null };
16231
16356
  try {
16232
- const parsed = JSON.parse(readFileSync16(filePath, "utf8"));
16357
+ const parsed = JSON.parse(readFileSync17(filePath, "utf8"));
16233
16358
  return { lastFocusedAt: parsed.lastFocusedAt ?? null };
16234
16359
  } catch {
16235
16360
  return { lastFocusedAt: null };
@@ -16260,16 +16385,16 @@ function nextRunnerLastError(pollError) {
16260
16385
  function resolveOverlordAppInvocation({
16261
16386
  platform: platform2 = process.platform,
16262
16387
  homedir: homedir2 = os4.homedir(),
16263
- exists = existsSync21
16388
+ exists = existsSync22
16264
16389
  } = {}) {
16265
16390
  if (platform2 !== "darwin") return null;
16266
16391
  const appDirs = [
16267
16392
  "/Applications/Overlord.app",
16268
- path25.join(homedir2, "Applications", "Overlord.app")
16393
+ path26.join(homedir2, "Applications", "Overlord.app")
16269
16394
  ];
16270
16395
  for (const appDir of appDirs) {
16271
- const program = path25.join(appDir, "Contents", "MacOS", "Overlord");
16272
- const script = path25.join(appDir, "Contents", "Resources", "cli", "bin", "ovld.mjs");
16396
+ const program = path26.join(appDir, "Contents", "MacOS", "Overlord");
16397
+ const script = path26.join(appDir, "Contents", "Resources", "cli", "bin", "ovld.mjs");
16273
16398
  if (exists(program) && exists(script)) {
16274
16399
  return { program, args: [script, "runner", "supervise"], runAsElectronNode: true };
16275
16400
  }
@@ -16281,7 +16406,7 @@ function resolveOvldInvocation(argv = process.argv, execPath = process.execPath)
16281
16406
  if (override) {
16282
16407
  return { program: override, args: ["runner", "supervise"] };
16283
16408
  }
16284
- const scriptPath = argv[1] ? path25.resolve(argv[1]) : "";
16409
+ const scriptPath = argv[1] ? path26.resolve(argv[1]) : "";
16285
16410
  if (process.env.ELECTRON_RUN_AS_NODE) {
16286
16411
  return scriptPath ? { program: execPath, args: [scriptPath, "runner", "supervise"], runAsElectronNode: true } : { program: execPath, args: ["runner", "supervise"], runAsElectronNode: true };
16287
16412
  }
@@ -16314,7 +16439,7 @@ function buildRunnerServiceEnv({
16314
16439
  PATH: process.env.PATH?.trim() || "/usr/local/bin:/usr/bin:/bin"
16315
16440
  };
16316
16441
  const home = overlordHome?.trim() || process.env.OVLD_HOME?.trim();
16317
- if (home) env.OVLD_HOME = path25.resolve(home);
16442
+ if (home) env.OVLD_HOME = path26.resolve(home);
16318
16443
  const token = process.env.OVERLORD_USER_TOKEN?.trim() || process.env.OVLD_USER_TOKEN?.trim();
16319
16444
  if (token) env.OVERLORD_USER_TOKEN = token;
16320
16445
  if (runAsElectronNode || process.env.ELECTRON_RUN_AS_NODE) env.ELECTRON_RUN_AS_NODE = "1";
@@ -16353,9 +16478,9 @@ ${envEntries}
16353
16478
  <key>KeepAlive</key>
16354
16479
  <true/>
16355
16480
  <key>StandardOutPath</key>
16356
- <string>${xmlEscape(path25.join(logDir, "runner-service.out.log"))}</string>
16481
+ <string>${xmlEscape(path26.join(logDir, "runner-service.out.log"))}</string>
16357
16482
  <key>StandardErrorPath</key>
16358
- <string>${xmlEscape(path25.join(logDir, "runner-service.err.log"))}</string>
16483
+ <string>${xmlEscape(path26.join(logDir, "runner-service.err.log"))}</string>
16359
16484
  <key>ProcessType</key>
16360
16485
  <string>Background</string>
16361
16486
  </dict>
@@ -16386,12 +16511,12 @@ WantedBy=default.target
16386
16511
  `;
16387
16512
  }
16388
16513
  function launchAgentsDir() {
16389
- return path25.join(os4.homedir(), "Library", "LaunchAgents");
16514
+ return path26.join(os4.homedir(), "Library", "LaunchAgents");
16390
16515
  }
16391
16516
  function systemdUserDir() {
16392
16517
  const xdg = process.env.XDG_CONFIG_HOME?.trim();
16393
- const base = xdg ? path25.resolve(xdg) : path25.join(os4.homedir(), ".config");
16394
- return path25.join(base, "systemd", "user");
16518
+ const base = xdg ? path26.resolve(xdg) : path26.join(os4.homedir(), ".config");
16519
+ return path26.join(base, "systemd", "user");
16395
16520
  }
16396
16521
  async function runCommand(program, args) {
16397
16522
  const { stdout } = await execFileAsync(program, args);
@@ -16420,19 +16545,19 @@ var init_runner_service = __esm({
16420
16545
  kind = "launchd";
16421
16546
  identifier = LAUNCHD_LABEL;
16422
16547
  unitPath() {
16423
- return path25.join(launchAgentsDir(), `${LAUNCHD_LABEL}.plist`);
16548
+ return path26.join(launchAgentsDir(), `${LAUNCHD_LABEL}.plist`);
16424
16549
  }
16425
16550
  render(opts) {
16426
16551
  return renderLaunchdPlist({
16427
16552
  label: LAUNCHD_LABEL,
16428
16553
  invocation: opts.invocation,
16429
16554
  env: opts.env,
16430
- logDir: path25.join(resolveGlobalDataDir(), "logs")
16555
+ logDir: path26.join(resolveGlobalDataDir(), "logs")
16431
16556
  });
16432
16557
  }
16433
16558
  async install(opts) {
16434
- mkdirSync10(launchAgentsDir(), { recursive: true });
16435
- mkdirSync10(path25.join(resolveGlobalDataDir(), "logs"), { recursive: true });
16559
+ mkdirSync11(launchAgentsDir(), { recursive: true });
16560
+ mkdirSync11(path26.join(resolveGlobalDataDir(), "logs"), { recursive: true });
16436
16561
  writeServiceFile(this.unitPath(), this.render(opts));
16437
16562
  if (opts.autoStart) await this.start();
16438
16563
  }
@@ -16462,10 +16587,10 @@ var init_runner_service = __esm({
16462
16587
  await this.stop();
16463
16588
  } catch {
16464
16589
  }
16465
- if (existsSync21(this.unitPath())) rmSync5(this.unitPath());
16590
+ if (existsSync22(this.unitPath())) rmSync5(this.unitPath());
16466
16591
  }
16467
16592
  async status() {
16468
- const installed = existsSync21(this.unitPath());
16593
+ const installed = existsSync22(this.unitPath());
16469
16594
  try {
16470
16595
  const { stdout } = await runCommand("launchctl", ["list"]);
16471
16596
  const line = stdout.split("\n").find((row) => row.includes(LAUNCHD_LABEL));
@@ -16481,13 +16606,13 @@ var init_runner_service = __esm({
16481
16606
  kind = "systemd";
16482
16607
  identifier = `${SYSTEMD_UNIT_NAME}.service`;
16483
16608
  unitPath() {
16484
- return path25.join(systemdUserDir(), `${SYSTEMD_UNIT_NAME}.service`);
16609
+ return path26.join(systemdUserDir(), `${SYSTEMD_UNIT_NAME}.service`);
16485
16610
  }
16486
16611
  render(opts) {
16487
16612
  return renderSystemdUnit(opts);
16488
16613
  }
16489
16614
  async install(opts) {
16490
- mkdirSync10(systemdUserDir(), { recursive: true });
16615
+ mkdirSync11(systemdUserDir(), { recursive: true });
16491
16616
  writeServiceFile(this.unitPath(), this.render(opts));
16492
16617
  await runCommand("systemctl", ["--user", "daemon-reload"]);
16493
16618
  await runCommand("systemctl", ["--user", "enable", this.identifier]);
@@ -16508,14 +16633,14 @@ var init_runner_service = __esm({
16508
16633
  await runCommand("systemctl", ["--user", "disable", this.identifier]);
16509
16634
  } catch {
16510
16635
  }
16511
- if (existsSync21(this.unitPath())) rmSync5(this.unitPath());
16636
+ if (existsSync22(this.unitPath())) rmSync5(this.unitPath());
16512
16637
  try {
16513
16638
  await runCommand("systemctl", ["--user", "daemon-reload"]);
16514
16639
  } catch {
16515
16640
  }
16516
16641
  }
16517
16642
  async status() {
16518
- const installed = existsSync21(this.unitPath());
16643
+ const installed = existsSync22(this.unitPath());
16519
16644
  try {
16520
16645
  const { stdout } = await runCommand("systemctl", ["--user", "is-active", this.identifier]);
16521
16646
  return { installed, running: stdout.trim() === "active" ? "running" : "stopped" };
@@ -16582,14 +16707,14 @@ var init_select_prompt = __esm({
16582
16707
 
16583
16708
  // src/session-key.ts
16584
16709
  import { createHash as createHash7 } from "node:crypto";
16585
- import { existsSync as existsSync22, mkdirSync as mkdirSync11, readFileSync as readFileSync17, rmSync as rmSync6, writeFileSync as writeFileSync10 } from "node:fs";
16586
- import path26 from "node:path";
16710
+ import { existsSync as existsSync23, mkdirSync as mkdirSync12, readFileSync as readFileSync18, rmSync as rmSync6, writeFileSync as writeFileSync11 } from "node:fs";
16711
+ import path27 from "node:path";
16587
16712
  function sessionKeyCachePath({
16588
16713
  missionId,
16589
16714
  workingDirectory
16590
16715
  }) {
16591
- const key = createHash7("sha256").update(`${path26.resolve(workingDirectory)}\0${missionId}`).digest("hex");
16592
- return path26.join(resolveGlobalDataDir(), "protocol-session-keys", key);
16716
+ const key = createHash7("sha256").update(`${path27.resolve(workingDirectory)}\0${missionId}`).digest("hex");
16717
+ return path27.join(resolveGlobalDataDir(), "protocol-session-keys", key);
16593
16718
  }
16594
16719
  function readCachedSessionKey({
16595
16720
  missionId,
@@ -16597,8 +16722,8 @@ function readCachedSessionKey({
16597
16722
  }) {
16598
16723
  try {
16599
16724
  const filePath = sessionKeyCachePath({ missionId, workingDirectory });
16600
- if (!existsSync22(filePath)) return void 0;
16601
- const raw = JSON.parse(readFileSync17(filePath, "utf8"));
16725
+ if (!existsSync23(filePath)) return void 0;
16726
+ const raw = JSON.parse(readFileSync18(filePath, "utf8"));
16602
16727
  return typeof raw.sessionKey === "string" && raw.sessionKey.trim() ? raw.sessionKey.trim() : void 0;
16603
16728
  } catch {
16604
16729
  return void 0;
@@ -16613,8 +16738,8 @@ function writeCachedSessionKey({
16613
16738
  const trimmed = sessionKey.trim();
16614
16739
  if (!trimmed) return;
16615
16740
  const filePath = sessionKeyCachePath({ missionId, workingDirectory });
16616
- mkdirSync11(path26.dirname(filePath), { recursive: true });
16617
- writeFileSync10(
16741
+ mkdirSync12(path27.dirname(filePath), { recursive: true });
16742
+ writeFileSync11(
16618
16743
  filePath,
16619
16744
  JSON.stringify({ sessionKey: trimmed, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }),
16620
16745
  { mode: 384 }
@@ -16628,7 +16753,7 @@ function clearCachedSessionKey({
16628
16753
  }) {
16629
16754
  try {
16630
16755
  const filePath = sessionKeyCachePath({ missionId, workingDirectory });
16631
- if (existsSync22(filePath)) rmSync6(filePath);
16756
+ if (existsSync23(filePath)) rmSync6(filePath);
16632
16757
  } catch {
16633
16758
  }
16634
16759
  }
@@ -16646,9 +16771,9 @@ __export(commands_exports, {
16646
16771
  runManagementCommand: () => runManagementCommand,
16647
16772
  runProtocolCommand: () => runProtocolCommand
16648
16773
  });
16649
- import { existsSync as existsSync23, readFileSync as readFileSync18 } from "node:fs";
16774
+ import { existsSync as existsSync24, readFileSync as readFileSync19 } from "node:fs";
16650
16775
  import os5 from "node:os";
16651
- import path27 from "node:path";
16776
+ import path28 from "node:path";
16652
16777
  function resourceAccessModeBody(value) {
16653
16778
  if (typeof value !== "string") return {};
16654
16779
  const normalized = value.trim().toLowerCase();
@@ -16665,7 +16790,7 @@ function writeProjectJsonFromResource({
16665
16790
  projectId,
16666
16791
  resource
16667
16792
  }) {
16668
- const record = asRecord2(resource);
16793
+ const record = asRecord3(resource);
16669
16794
  if (typeof record.id !== "string") return;
16670
16795
  if (record.accessMode === "read") return;
16671
16796
  writeProjectJson({
@@ -16694,7 +16819,7 @@ function readChangedFilesFromFlags(flags, stdin) {
16694
16819
  if (typeof fileFlag === "string") {
16695
16820
  const raw = fileFlag === "-" ? stdin ?? "" : (() => {
16696
16821
  try {
16697
- return readFileSync18(fileFlag, "utf8");
16822
+ return readFileSync19(fileFlag, "utf8");
16698
16823
  } catch {
16699
16824
  return "";
16700
16825
  }
@@ -16746,7 +16871,7 @@ function readJsonFlagContent({
16746
16871
  if (typeof filePath === "string") {
16747
16872
  if (fileInputs[fileFlag] !== void 0) return fileInputs[fileFlag];
16748
16873
  try {
16749
- return readFileSync18(filePath, "utf8");
16874
+ return readFileSync19(filePath, "utf8");
16750
16875
  } catch {
16751
16876
  return void 0;
16752
16877
  }
@@ -16969,7 +17094,7 @@ async function resolveTerminalLaunchSettings({
16969
17094
  return { terminalLauncher: null };
16970
17095
  }
16971
17096
  }
16972
- function asRecord2(value) {
17097
+ function asRecord3(value) {
16973
17098
  return value && typeof value === "object" ? value : {};
16974
17099
  }
16975
17100
  function parsePreLaunchCommandsValue(value) {
@@ -17004,32 +17129,32 @@ async function recordBranchPrepared({
17004
17129
  });
17005
17130
  }
17006
17131
  function firstObjectiveId(mission) {
17007
- const objectives = asRecord2(mission).objectives;
17132
+ const objectives = asRecord3(mission).objectives;
17008
17133
  if (!Array.isArray(objectives)) return void 0;
17009
17134
  const first = objectives[0];
17010
- const id = asRecord2(first).id;
17135
+ const id = asRecord3(first).id;
17011
17136
  return typeof id === "string" ? id : void 0;
17012
17137
  }
17013
17138
  function launchableObjectiveId(mission) {
17014
- const objectives = asRecord2(mission).objectives;
17139
+ const objectives = asRecord3(mission).objectives;
17015
17140
  if (!Array.isArray(objectives)) return void 0;
17016
17141
  const launchableStates = ["executing", "submitted", "launching", "draft"];
17017
17142
  for (const state of launchableStates) {
17018
- const match = objectives.find((objective) => asRecord2(objective).state === state);
17019
- const id = asRecord2(match).id;
17143
+ const match = objectives.find((objective) => asRecord3(objective).state === state);
17144
+ const id = asRecord3(match).id;
17020
17145
  if (typeof id === "string") return id;
17021
17146
  }
17022
17147
  return firstObjectiveId(mission);
17023
17148
  }
17024
17149
  function objectiveAssignedAgent(mission, objectiveId) {
17025
- const objectives = asRecord2(mission).objectives;
17150
+ const objectives = asRecord3(mission).objectives;
17026
17151
  if (!Array.isArray(objectives)) return void 0;
17027
- const match = objectives.find((objective) => asRecord2(objective).id === objectiveId);
17028
- const agent = asRecord2(match).assignedAgent;
17152
+ const match = objectives.find((objective) => asRecord3(objective).id === objectiveId);
17153
+ const agent = asRecord3(match).assignedAgent;
17029
17154
  return typeof agent === "string" && agent.trim() ? agent.trim() : void 0;
17030
17155
  }
17031
17156
  function missionDisplayId(mission) {
17032
- const record = asRecord2(mission);
17157
+ const record = asRecord3(mission);
17033
17158
  return typeof record.displayId === "string" ? record.displayId : typeof record.id === "string" ? record.id : "unknown";
17034
17159
  }
17035
17160
  async function resolveProtocolFileInputs({
@@ -17050,7 +17175,7 @@ async function resolveProtocolFileInputs({
17050
17175
  } else if (process.stdin.isTTY) {
17051
17176
  stdinContent = "";
17052
17177
  } else {
17053
- stdinContent = readFileSync18(0, "utf8");
17178
+ stdinContent = readFileSync19(0, "utf8");
17054
17179
  }
17055
17180
  return stdinContent;
17056
17181
  };
@@ -17064,7 +17189,7 @@ async function resolveProtocolFileInputs({
17064
17189
  fileInputs[flagName] = content;
17065
17190
  stdinPayload = content;
17066
17191
  } else {
17067
- fileInputs[flagName] = readFileSync18(filePath, "utf8");
17192
+ fileInputs[flagName] = readFileSync19(filePath, "utf8");
17068
17193
  }
17069
17194
  }
17070
17195
  if (stdinPayload === void 0 && stdin !== void 0 && Object.keys(fileInputs).length === 0) {
@@ -17076,7 +17201,7 @@ async function discoverProjectId(runtime, explicit) {
17076
17201
  if (explicit) return explicit;
17077
17202
  const projects = await listAccessibleProjects({ backend: runtime.backend });
17078
17203
  const first = projects[0];
17079
- const id = asRecord2(first).id;
17204
+ const id = asRecord3(first).id;
17080
17205
  if (typeof id !== "string") {
17081
17206
  throw new CliError({ message: "No project found. Create one with `ovld create-project`." });
17082
17207
  }
@@ -17107,7 +17232,7 @@ async function runProtocolCommand({
17107
17232
  });
17108
17233
  if (subcommand === "record-touched") {
17109
17234
  const missionOverride = flagValue(parsed.flags, "--mission-id") ?? process.env.MISSION_ID ?? process.env.OVERLORD_MISSION_ID;
17110
- const rawPayload = stdin ?? (process.stdin.isTTY ? "" : readFileSync18(0, "utf8"));
17235
+ const rawPayload = stdin ?? (process.stdin.isTTY ? "" : readFileSync19(0, "utf8"));
17111
17236
  const result2 = recordTouchedFromPayload({
17112
17237
  rawPayload,
17113
17238
  missionOverride,
@@ -17218,7 +17343,7 @@ async function runProtocolCommand({
17218
17343
  resetTouchedFiles({ workingDirectory, missionId });
17219
17344
  resetRationaleNotes({ workingDirectory, missionId });
17220
17345
  }
17221
- const resultRecord = asRecord2(result);
17346
+ const resultRecord = asRecord3(result);
17222
17347
  if (typeof resultRecord.sessionKey === "string") {
17223
17348
  printKeyValue({ SESSION_KEY: resultRecord.sessionKey });
17224
17349
  if (missionId) {
@@ -17233,7 +17358,7 @@ async function runProtocolCommand({
17233
17358
  }
17234
17359
  }
17235
17360
  if (subcommand === "attach" || subcommand === "connect" || subcommand === "resume-follow-up") {
17236
- const missionRecord = asRecord2(resultRecord.mission);
17361
+ const missionRecord = asRecord3(resultRecord.mission);
17237
17362
  const displayId = typeof missionRecord.displayId === "string" && missionRecord.displayId.trim() || typeof missionId === "string" && missionId.trim() || typeof resultRecord.missionId === "string" && resultRecord.missionId.trim() || "";
17238
17363
  const title = typeof missionRecord.title === "string" ? missionRecord.title : void 0;
17239
17364
  const pointerMissionId = typeof missionRecord.id === "string" && missionRecord.id.trim() || typeof resultRecord.missionId === "string" && resultRecord.missionId.trim() || displayId;
@@ -17253,8 +17378,8 @@ async function runProtocolCommand({
17253
17378
  clearCachedSessionKey({ missionId, workingDirectory });
17254
17379
  removeActiveSession({ workingDirectory, missionId });
17255
17380
  clearActiveMissionPointer(workingDirectory);
17256
- const connectorInstallsEditHook = existsSync23(path27.join(os5.homedir(), ".claude")) || existsSync23(
17257
- path27.join(
17381
+ const connectorInstallsEditHook = existsSync24(path28.join(os5.homedir(), ".claude")) || existsSync24(
17382
+ path28.join(
17258
17383
  os5.homedir(),
17259
17384
  ".cursor",
17260
17385
  "plugins",
@@ -17303,7 +17428,7 @@ async function runProtocolCommand({
17303
17428
  if (subcommand === "attachment-list" && Array.isArray(result)) {
17304
17429
  const baseUrl = runtime.backend.baseUrl;
17305
17430
  const enhanced = result.map((entry) => {
17306
- const rec = asRecord2(entry);
17431
+ const rec = asRecord3(entry);
17307
17432
  const relUrl = rec.url;
17308
17433
  return typeof relUrl === "string" && relUrl.startsWith("/") ? { ...rec, url: `${baseUrl}${relUrl}` } : rec;
17309
17434
  });
@@ -17328,7 +17453,7 @@ async function runManagementCommand({
17328
17453
  path: "/api/projects",
17329
17454
  body: { name }
17330
17455
  });
17331
- const projectId = asRecord2(project).id;
17456
+ const projectId = asRecord3(project).id;
17332
17457
  if (!flagBoolean(parsed.flags, "--no-directory") && typeof projectId === "string") {
17333
17458
  const directory = flagValue(parsed.flags, "--directory") ?? process.cwd();
17334
17459
  const resource = await runtime.backend.post({
@@ -17343,7 +17468,7 @@ async function runManagementCommand({
17343
17468
  if (json) printJson({ project });
17344
17469
  else
17345
17470
  console.log(
17346
- `Created project ${asRecord2(project).name ?? name} (${projectId ?? "unknown"})`
17471
+ `Created project ${asRecord3(project).name ?? name} (${projectId ?? "unknown"})`
17347
17472
  );
17348
17473
  return;
17349
17474
  }
@@ -17354,7 +17479,7 @@ async function runManagementCommand({
17354
17479
  case "add-cwd": {
17355
17480
  const directory = flagValue(parsed.flags, "--directory") ?? process.cwd();
17356
17481
  const existingProjectJson = readProjectJsonLink(
17357
- path27.join(directory, ".overlord", "project.json")
17482
+ path28.join(directory, ".overlord", "project.json")
17358
17483
  );
17359
17484
  const resourceKey = flagValue(parsed.flags, "--key") ?? existingProjectJson?.resourceKey;
17360
17485
  let projectId = flagValue(parsed.flags, "--project-id");
@@ -17420,7 +17545,7 @@ async function runManagementCommand({
17420
17545
  path: "/api/protocol/register-target",
17421
17546
  body: { args: rest, positional: parsed.positional, flags: protocolFlags, fileInputs: {} }
17422
17547
  });
17423
- const record = asRecord2(result);
17548
+ const record = asRecord3(result);
17424
17549
  if (record.status === "workspace_selection_required") {
17425
17550
  if (json) {
17426
17551
  printJson({ result });
@@ -17430,7 +17555,7 @@ async function runManagementCommand({
17430
17555
  "You belong to more than one workspace. Re-run with --workspace-id set to one of:"
17431
17556
  );
17432
17557
  for (const entry of workspaces) {
17433
- const ws = asRecord2(entry);
17558
+ const ws = asRecord3(entry);
17434
17559
  console.log(` - ${ws.name ?? ws.id} (${ws.slug ?? ws.id})`);
17435
17560
  }
17436
17561
  }
@@ -17439,8 +17564,8 @@ async function runManagementCommand({
17439
17564
  if (json) {
17440
17565
  printJson({ result });
17441
17566
  } else {
17442
- const target = asRecord2(record.executionTarget);
17443
- const ws = asRecord2(record.workspace);
17567
+ const target = asRecord3(record.executionTarget);
17568
+ const ws = asRecord3(record.workspace);
17444
17569
  console.log(
17445
17570
  `Registered execution target ${target.label ?? name ?? ""} (${target.executionTargetId ?? "unknown"}) in workspace ${ws.name ?? ws.id ?? ""}`
17446
17571
  );
@@ -17475,7 +17600,7 @@ async function runManagementCommand({
17475
17600
  }
17476
17601
  });
17477
17602
  if (objectivesJson) {
17478
- const missionObjectives = asRecord2(mission).objectives;
17603
+ const missionObjectives = asRecord3(mission).objectives;
17479
17604
  if (Array.isArray(missionObjectives) && missionObjectives.length !== objectives.length) {
17480
17605
  throw new CliError({
17481
17606
  message: `Backend created ${missionObjectives.length} objective(s), expected ${objectives.length}`
@@ -17543,10 +17668,10 @@ async function runManagementCommand({
17543
17668
  const executionTargetId = await resolvePreferredExecutionTargetId({
17544
17669
  backend: scopedRuntime.backend
17545
17670
  });
17546
- const missionProjectId = asRecord2(mission).projectId;
17671
+ const missionProjectId = asRecord3(mission).projectId;
17547
17672
  const projectLaunchSettings = typeof missionProjectId === "string" ? await scopedRuntime.backend.get(`/api/projects/${encodeURIComponent(missionProjectId)}`).then((project) => ({
17548
- preLaunchCommands: parsePreLaunchCommandsValue(asRecord2(project).preLaunchCommands),
17549
- launchEnvVars: parseLaunchEnvVarsValue(asRecord2(project).launchEnvVars)
17673
+ preLaunchCommands: parsePreLaunchCommandsValue(asRecord3(project).preLaunchCommands),
17674
+ launchEnvVars: parseLaunchEnvVarsValue(asRecord3(project).launchEnvVars)
17550
17675
  })).catch(() => ({
17551
17676
  preLaunchCommands: [],
17552
17677
  launchEnvVars: {}
@@ -17621,7 +17746,7 @@ async function runManagementCommand({
17621
17746
  if (json) printJson({ missions });
17622
17747
  else {
17623
17748
  for (const mission of missions) {
17624
- const record = asRecord2(mission);
17749
+ const record = asRecord3(mission);
17625
17750
  console.log(
17626
17751
  `${record.displayId ?? record.id} ${record.statusType ?? ""} ${record.title ?? ""}`
17627
17752
  );
@@ -17644,13 +17769,13 @@ async function runManagementCommand({
17644
17769
  rationales: `/api/missions/${encodeURIComponent(missionId)}/file-changes`,
17645
17770
  deliveries: `/api/missions/${encodeURIComponent(missionId)}/deliveries`
17646
17771
  };
17647
- const path28 = sub ? pathBySub[sub] : void 0;
17648
- if (!path28) {
17772
+ const path29 = sub ? pathBySub[sub] : void 0;
17773
+ if (!path29) {
17649
17774
  throw new CliError({
17650
17775
  message: "Usage: ovld mission context|events|deliveries|artifacts|rationales <missionId> [--json]"
17651
17776
  });
17652
17777
  }
17653
- const result = await runtime.backend.get(path28);
17778
+ const result = await runtime.backend.get(path29);
17654
17779
  if (json || sub === "context") printJson(result);
17655
17780
  else if (Array.isArray(result)) for (const row of result) console.log(JSON.stringify(row));
17656
17781
  else printJson(result);
@@ -17673,6 +17798,10 @@ async function runManagementCommand({
17673
17798
  throw new CliError({ message: `Unknown command: ${command}` });
17674
17799
  }
17675
17800
  }
17801
+ function isNoExecutionTargetRegisteredError(error) {
17802
+ const message = error instanceof Error ? error.message : String(error);
17803
+ return message.includes("(no_execution_target_registered)");
17804
+ }
17676
17805
  async function runRunnerCommand({
17677
17806
  runtime,
17678
17807
  parsed,
@@ -17694,7 +17823,7 @@ async function runRunnerCommand({
17694
17823
  }
17695
17824
  });
17696
17825
  if (json) printJson(result);
17697
- else console.log(`Cleared ${asRecord2(result).cleared ?? 0} execution request(s).`);
17826
+ else console.log(`Cleared ${asRecord3(result).cleared ?? 0} execution request(s).`);
17698
17827
  return;
17699
17828
  }
17700
17829
  if (sub === "service") {
@@ -17707,17 +17836,32 @@ async function runRunnerCommand({
17707
17836
  });
17708
17837
  }
17709
17838
  const runOnce = async () => {
17710
- const claim = await runtime.backend.post({
17711
- path: "/api/runner/claim",
17712
- body: {
17713
- projectId: flagValue(parsed.flags, "--project-id"),
17714
- ...clientDeviceIdentity()
17839
+ let claim;
17840
+ try {
17841
+ claim = await runtime.backend.post({
17842
+ path: "/api/runner/claim",
17843
+ body: {
17844
+ projectId: flagValue(parsed.flags, "--project-id"),
17845
+ ...clientDeviceIdentity(),
17846
+ // Contract v40: the claim poll doubles as this runner instance's
17847
+ // heartbeat, so local target liveness reflects a runner that can
17848
+ // actually take work rather than any CLI traffic from the machine.
17849
+ ...runnerRegistrationPayload()
17850
+ }
17851
+ });
17852
+ } catch (error) {
17853
+ if (isNoExecutionTargetRegisteredError(error)) {
17854
+ throw new CliError({
17855
+ message: `${error instanceof Error ? error.message : String(error)}
17856
+ The runner will not register a target for you \u2014 declare this machine first, then start it again.`
17857
+ });
17715
17858
  }
17716
- });
17717
- const request = asRecord2(claim).request;
17718
- const longPoll = asRecord2(claim).longPoll === true;
17859
+ throw error;
17860
+ }
17861
+ const request = asRecord3(claim).request;
17862
+ const longPoll = asRecord3(claim).longPoll === true;
17719
17863
  if (!request) return { launched: false, longPoll };
17720
- const requestRecord = asRecord2(request);
17864
+ const requestRecord = asRecord3(request);
17721
17865
  const requestId = String(requestRecord.id);
17722
17866
  const projectId = String(requestRecord.projectId ?? "");
17723
17867
  const executionTargetId = typeof requestRecord.executionTargetId === "string" ? requestRecord.executionTargetId.trim() : "";
@@ -17757,7 +17901,7 @@ async function runRunnerCommand({
17757
17901
  message: `Execution request ${requestId} has no agent; the objective must specify one before it can be launched.`
17758
17902
  });
17759
17903
  }
17760
- const launchConfig = asRecord2(requestRecord.launchConfig);
17904
+ const launchConfig = asRecord3(requestRecord.launchConfig);
17761
17905
  const terminal = await resolveTerminalLaunchSettings({ runtime, flags: parsed.flags });
17762
17906
  const missionId = String(requestRecord.missionId);
17763
17907
  const dryRun = flagBoolean(parsed.flags, "--dry-run");
@@ -17848,6 +17992,7 @@ async function runRunnerSupervisor({
17848
17992
  try {
17849
17993
  result = await runOnce();
17850
17994
  } catch (error) {
17995
+ if (isNoExecutionTargetRegisteredError(error)) throw error;
17851
17996
  lastError = error instanceof Error ? error.message : String(error);
17852
17997
  }
17853
17998
  const state = readRunnerServiceState();
@@ -17998,6 +18143,7 @@ var init_commands = __esm({
17998
18143
  init_protocol_help();
17999
18144
  init_record_touched();
18000
18145
  init_resource_observations();
18146
+ init_runner_identity();
18001
18147
  init_runner_service();
18002
18148
  init_select_prompt();
18003
18149
  init_session_key();