overlord-cli 0.2607291136.0 → 0.2607301714.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
  }));
@@ -12380,8 +12437,102 @@ var init_util2 = __esm({
12380
12437
  });
12381
12438
 
12382
12439
  // ../packages/core/dist/service/local-target/project-metadata.js
12383
- import { existsSync as existsSync11, mkdirSync as mkdirSync5, readFileSync as readFileSync9, writeFileSync as writeFileSync4 } from "node:fs";
12440
+ import { execFileSync } from "node:child_process";
12441
+ import { chmodSync as chmodSync3, existsSync as existsSync11, mkdirSync as mkdirSync5, readFileSync as readFileSync9, writeFileSync as writeFileSync4 } from "node:fs";
12384
12442
  import path11 from "node:path";
12443
+ function writeIfChanged(filePath, content) {
12444
+ if (!existsSync11(filePath) || readFileSync9(filePath, "utf8") !== content) {
12445
+ writeFileSync4(filePath, content);
12446
+ }
12447
+ }
12448
+ function replaceManagedBlock(content, block) {
12449
+ const blockPattern = new RegExp(`${INSTRUCTION_BLOCK_START}[\\s\\S]*?${INSTRUCTION_BLOCK_END}\\n?`, "g");
12450
+ const withoutExisting = content.replace(blockPattern, "").trimEnd();
12451
+ return `${withoutExisting}${withoutExisting ? "\n\n" : ""}${block}
12452
+ `;
12453
+ }
12454
+ function ensureAgentInstructions(checkoutPath) {
12455
+ for (const filename of ["AGENTS.md", "CLAUDE.md"]) {
12456
+ const instructionPath = path11.join(checkoutPath, filename);
12457
+ const existing = existsSync11(instructionPath) ? readFileSync9(instructionPath, "utf8") : "";
12458
+ writeIfChanged(instructionPath, replaceManagedBlock(existing, PROJECT_METADATA_INSTRUCTION));
12459
+ }
12460
+ }
12461
+ function ensureGitignore(checkoutPath) {
12462
+ const gitignorePath = path11.join(checkoutPath, ".gitignore");
12463
+ const existing = existsSync11(gitignorePath) ? readFileSync9(gitignorePath, "utf8") : "";
12464
+ const existingPatterns = new Set(existing.split(/\r?\n/).map((line) => line.trim().replace(/^\//, "")).filter(Boolean));
12465
+ const additions = [".overlord/tmp/", ".overlord/logs/"].filter((pattern) => !existingPatterns.has(pattern));
12466
+ if (additions.length === 0)
12467
+ return;
12468
+ const separator = existing.length === 0 || existing.endsWith("\n") ? "" : "\n";
12469
+ writeFileSync4(gitignorePath, `${existing}${separator}${additions.join("\n")}
12470
+ `);
12471
+ }
12472
+ function resolveGitRoot(directoryPath) {
12473
+ try {
12474
+ return execFileSync("git", ["-C", directoryPath, "rev-parse", "--show-toplevel"], {
12475
+ encoding: "utf8",
12476
+ stdio: ["ignore", "pipe", "ignore"]
12477
+ }).trim();
12478
+ } catch {
12479
+ return null;
12480
+ }
12481
+ }
12482
+ function resolveGitHooksDirectory(gitRoot) {
12483
+ try {
12484
+ const gitPath2 = execFileSync("git", ["-C", gitRoot, "rev-parse", "--git-path", "hooks"], {
12485
+ encoding: "utf8",
12486
+ stdio: ["ignore", "pipe", "ignore"]
12487
+ }).trim();
12488
+ return path11.isAbsolute(gitPath2) ? gitPath2 : path11.resolve(gitRoot, gitPath2);
12489
+ } catch {
12490
+ return null;
12491
+ }
12492
+ }
12493
+ function ensurePreCommitGuard(gitRoot) {
12494
+ const hooksDirectory = resolveGitHooksDirectory(gitRoot);
12495
+ if (!hooksDirectory)
12496
+ return;
12497
+ mkdirSync5(hooksDirectory, { recursive: true });
12498
+ const guardPath = path11.join(hooksDirectory, HOOK_GUARD_FILENAME);
12499
+ writeIfChanged(guardPath, `#!/bin/sh
12500
+ # Managed by Overlord: reject any staged project-link metadata change.
12501
+ if git diff --cached --quiet -- .overlord/project.json; then
12502
+ exit 0
12503
+ fi
12504
+ echo "Overlord blocked this commit: .overlord/project.json is managed metadata and must not be changed." >&2
12505
+ exit 1
12506
+ `);
12507
+ chmodSync3(guardPath, 493);
12508
+ const preCommitPath = path11.join(hooksDirectory, "pre-commit");
12509
+ const hookBlock = `${HOOK_BLOCK_START}
12510
+ "$(dirname "$0")/${HOOK_GUARD_FILENAME}" || exit $?
12511
+ ${HOOK_BLOCK_END}`;
12512
+ if (!existsSync11(preCommitPath)) {
12513
+ writeFileSync4(preCommitPath, `#!/bin/sh
12514
+ ${hookBlock}
12515
+ `);
12516
+ chmodSync3(preCommitPath, 493);
12517
+ return;
12518
+ }
12519
+ const existing = readFileSync9(preCommitPath, "utf8");
12520
+ const blockPattern = new RegExp(`${HOOK_BLOCK_START}[\\s\\S]*?${HOOK_BLOCK_END}\\n?`, "g");
12521
+ const updated = `${existing.replace(blockPattern, "").trimEnd()}
12522
+
12523
+ ${hookBlock}
12524
+ `;
12525
+ writeIfChanged(preCommitPath, updated);
12526
+ chmodSync3(preCommitPath, 493);
12527
+ }
12528
+ function protectProjectMetadata(directoryPath) {
12529
+ const gitRoot = resolveGitRoot(directoryPath);
12530
+ const checkoutPath = gitRoot ?? directoryPath;
12531
+ ensureAgentInstructions(checkoutPath);
12532
+ ensureGitignore(checkoutPath);
12533
+ if (gitRoot)
12534
+ ensurePreCommitGuard(gitRoot);
12535
+ }
12385
12536
  function parseProjectJson(projectJsonPath) {
12386
12537
  if (!existsSync11(projectJsonPath))
12387
12538
  return null;
@@ -12389,12 +12540,13 @@ function parseProjectJson(projectJsonPath) {
12389
12540
  if (typeof parsed.projectId !== "string" || typeof parsed.resourceId !== "string")
12390
12541
  return null;
12391
12542
  const resourceIdsByExecutionTarget = parsed.resourceIdsByExecutionTarget && typeof parsed.resourceIdsByExecutionTarget === "object" && !Array.isArray(parsed.resourceIdsByExecutionTarget) ? Object.fromEntries(Object.entries(parsed.resourceIdsByExecutionTarget).filter((entry) => typeof entry[0] === "string" && entry[0].trim().length > 0 && typeof entry[1] === "string" && entry[1].trim().length > 0)) : {};
12543
+ const resourceKey = typeof parsed.resourceKey === "string" && parsed.resourceKey.trim().length > 0 ? parsed.resourceKey.trim() : void 0;
12392
12544
  return {
12393
- _warning: typeof parsed._warning === "string" ? parsed._warning : "This file is managed by Overlord and is regenerated automatically when this folder is linked as a project resource. Do not edit it manually \u2014 manual changes will be overwritten.",
12545
+ _warning: typeof parsed._warning === "string" ? parsed._warning : PROJECT_JSON_WARNING,
12394
12546
  version: typeof parsed.version === "number" ? parsed.version : 1,
12395
12547
  projectId: parsed.projectId,
12396
12548
  resourceId: parsed.resourceId,
12397
- resourceKey: typeof parsed.resourceKey === "string" && parsed.resourceKey.trim().length > 0 ? parsed.resourceKey.trim() : void 0,
12549
+ ...resourceKey ? { resourceKey } : {},
12398
12550
  resourceIdsByExecutionTarget,
12399
12551
  isPrimary: parsed.isPrimary === true,
12400
12552
  linkedAt: typeof parsed.linkedAt === "string" ? parsed.linkedAt : nowIso()
@@ -12419,6 +12571,7 @@ function writeProjectJson({ directoryPath, projectId, resourceId, resourceKey, e
12419
12571
  mkdirSync5(overlordDir, { recursive: true });
12420
12572
  mkdirSync5(path11.join(overlordDir, "tmp"), { recursive: true });
12421
12573
  mkdirSync5(path11.join(overlordDir, "logs"), { recursive: true });
12574
+ protectProjectMetadata(directoryPath);
12422
12575
  const projectJsonPath = path11.join(overlordDir, "project.json");
12423
12576
  const existing = readProjectJsonLink(projectJsonPath);
12424
12577
  const resourceIdsByExecutionTarget = {
@@ -12428,7 +12581,7 @@ function writeProjectJson({ directoryPath, projectId, resourceId, resourceKey, e
12428
12581
  resourceIdsByExecutionTarget[executionTargetId.trim()] = resourceId;
12429
12582
  }
12430
12583
  writeFileSync4(projectJsonPath, `${JSON.stringify({
12431
- _warning: "This file is managed by Overlord and is regenerated automatically when this folder is linked as a project resource. Do not edit it manually \u2014 manual changes will be overwritten.",
12584
+ _warning: PROJECT_JSON_WARNING,
12432
12585
  version: PROJECT_JSON_VERSION,
12433
12586
  projectId,
12434
12587
  resourceId,
@@ -12440,21 +12593,34 @@ function writeProjectJson({ directoryPath, projectId, resourceId, resourceKey, e
12440
12593
  `);
12441
12594
  return projectJsonPath;
12442
12595
  }
12443
- var PROJECT_JSON_VERSION;
12596
+ var PROJECT_JSON_VERSION, PROJECT_JSON_WARNING, INSTRUCTION_BLOCK_START, INSTRUCTION_BLOCK_END, PROJECT_METADATA_INSTRUCTION, HOOK_GUARD_FILENAME, HOOK_BLOCK_START, HOOK_BLOCK_END;
12444
12597
  var init_project_metadata = __esm({
12445
12598
  "../packages/core/dist/service/local-target/project-metadata.js"() {
12446
12599
  "use strict";
12447
12600
  init_util2();
12448
12601
  PROJECT_JSON_VERSION = 2;
12602
+ PROJECT_JSON_WARNING = "STRICTLY PROTECTED: This file is managed exclusively by Overlord. Agents and users must not edit, replace, stage, commit, or delete it. Re-link the resource with Overlord to change it.";
12603
+ INSTRUCTION_BLOCK_START = "<!-- OVERLORD PROJECT METADATA PROTECTION: START -->";
12604
+ INSTRUCTION_BLOCK_END = "<!-- OVERLORD PROJECT METADATA PROTECTION: END -->";
12605
+ PROJECT_METADATA_INSTRUCTION = `${INSTRUCTION_BLOCK_START}
12606
+ ## Overlord project metadata \u2014 do not edit
12607
+
12608
+ \`.overlord/project.json\` is exclusively managed by Overlord. Do not edit,
12609
+ replace, stage, commit, delete, or revert it. If its link metadata needs to
12610
+ change, use Overlord's resource-linking command instead.
12611
+ ${INSTRUCTION_BLOCK_END}`;
12612
+ HOOK_GUARD_FILENAME = "overlord-project-json-guard";
12613
+ HOOK_BLOCK_START = "# >>> Overlord project metadata guard >>>";
12614
+ HOOK_BLOCK_END = "# <<< Overlord project metadata guard <<<";
12449
12615
  }
12450
12616
  });
12451
12617
 
12452
12618
  // ../packages/core/dist/repository/git-tree.js
12453
- import { execFileSync } from "node:child_process";
12619
+ import { execFileSync as execFileSync2 } from "node:child_process";
12454
12620
  import path12 from "node:path";
12455
12621
  function runGit(cwd, args) {
12456
12622
  try {
12457
- return execFileSync("git", args, {
12623
+ return execFileSync2("git", args, {
12458
12624
  cwd,
12459
12625
  encoding: "utf8",
12460
12626
  maxBuffer: 10 * 1024 * 1024,
@@ -12542,10 +12708,10 @@ var init_git_tree = __esm({
12542
12708
  });
12543
12709
 
12544
12710
  // ../packages/core/dist/service/local-target/git-run.js
12545
- import { execFileSync as execFileSync2 } from "node:child_process";
12711
+ import { execFileSync as execFileSync3 } from "node:child_process";
12546
12712
  function runGit2(cwd, args) {
12547
12713
  try {
12548
- return execFileSync2("git", args, {
12714
+ return execFileSync3("git", args, {
12549
12715
  cwd,
12550
12716
  encoding: "utf8",
12551
12717
  stdio: ["ignore", "pipe", "ignore"],
@@ -12557,7 +12723,7 @@ function runGit2(cwd, args) {
12557
12723
  }
12558
12724
  function runGitResult(cwd, args) {
12559
12725
  try {
12560
- const stdout = execFileSync2("git", args, {
12726
+ const stdout = execFileSync3("git", args, {
12561
12727
  cwd,
12562
12728
  encoding: "utf8",
12563
12729
  stdio: ["ignore", "pipe", "pipe"],
@@ -12944,10 +13110,10 @@ var init_commit_message_diff_git = __esm({
12944
13110
  });
12945
13111
 
12946
13112
  // ../packages/core/dist/service/local-target/doctor-checks.js
12947
- import { execFileSync as execFileSync3 } from "node:child_process";
13113
+ import { execFileSync as execFileSync4 } from "node:child_process";
12948
13114
  function commandOnPath(command, args) {
12949
13115
  try {
12950
- const detail = execFileSync3(command, args, {
13116
+ const detail = execFileSync4(command, args, {
12951
13117
  encoding: "utf8",
12952
13118
  stdio: ["ignore", "pipe", "ignore"]
12953
13119
  }).trim();
@@ -13441,13 +13607,13 @@ var init_branch_planning = __esm({
13441
13607
  });
13442
13608
 
13443
13609
  // src/branch-preparation.ts
13444
- import { execFileSync as execFileSync4 } from "node:child_process";
13610
+ import { execFileSync as execFileSync5 } from "node:child_process";
13445
13611
  import { existsSync as existsSync17, mkdirSync as mkdirSync7, statSync as statSync3 } from "node:fs";
13446
13612
  import os3 from "node:os";
13447
13613
  import path17 from "node:path";
13448
13614
  function runGit3(cwd, args, options = {}) {
13449
13615
  try {
13450
- return execFileSync4("git", args, {
13616
+ return execFileSync5("git", args, {
13451
13617
  cwd,
13452
13618
  encoding: "utf8",
13453
13619
  stdio: ["ignore", "pipe", "pipe"],
@@ -13462,7 +13628,7 @@ function runGit3(cwd, args, options = {}) {
13462
13628
  function lines(value) {
13463
13629
  return value.split("\n").map((line) => line.trim()).filter(Boolean);
13464
13630
  }
13465
- function resolveGitRoot(workingDirectory) {
13631
+ function resolveGitRoot2(workingDirectory) {
13466
13632
  const root = runGit3(workingDirectory, ["rev-parse", "--show-toplevel"]);
13467
13633
  if (!root) throw new Error(`${workingDirectory} is not inside a git repository.`);
13468
13634
  return path17.resolve(root);
@@ -13687,7 +13853,7 @@ async function prepareMissionBranch({
13687
13853
  if (options.dryRun) {
13688
13854
  return { workingDirectory: options.workingDirectory, branchAutomation: null };
13689
13855
  }
13690
- const gitRoot = resolveGitRoot(options.workingDirectory);
13856
+ const gitRoot = resolveGitRoot2(options.workingDirectory);
13691
13857
  const mission = await runtime.backend.get(
13692
13858
  `/api/missions/${encodeURIComponent(options.missionId)}`
13693
13859
  );
@@ -13891,10 +14057,10 @@ function primaryResourcePath(projectResources) {
13891
14057
  for (const entry of projectResources) {
13892
14058
  if (!entry || typeof entry !== "object") continue;
13893
14059
  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;
14060
+ const path29 = typeof record.path === "string" ? record.path.trim() : "";
14061
+ if (!path29) continue;
14062
+ if (record.isPrimary === true) return path29;
14063
+ if (record.isCurrent === true && !currentPath) currentPath = path29;
13898
14064
  }
13899
14065
  return currentPath;
13900
14066
  }
@@ -14316,7 +14482,7 @@ var init_terminal_launcher = __esm({
14316
14482
 
14317
14483
  // src/launch.ts
14318
14484
  import { spawnSync as spawnSync2 } from "node:child_process";
14319
- import { chmodSync as chmodSync3, writeFileSync as writeFileSync6 } from "node:fs";
14485
+ import { chmodSync as chmodSync4, writeFileSync as writeFileSync6 } from "node:fs";
14320
14486
  import path19 from "node:path";
14321
14487
  function overlordLaunchEnv({
14322
14488
  backendUrl,
@@ -14332,21 +14498,21 @@ function overlordLaunchEnv({
14332
14498
  ...projectResources && projectResources.length > 0 ? { OVERLORD_PROJECT_RESOURCES: JSON.stringify(projectResources) } : {}
14333
14499
  };
14334
14500
  }
14335
- function asRecord(value) {
14501
+ function asRecord2(value) {
14336
14502
  return value && typeof value === "object" ? value : {};
14337
14503
  }
14338
14504
  async function loadMissionContext({
14339
14505
  runtime,
14340
14506
  missionId
14341
14507
  }) {
14342
- const mission = asRecord(
14508
+ const mission = asRecord2(
14343
14509
  await runtime.backend.get(`/api/missions/${encodeURIComponent(missionId)}`)
14344
14510
  );
14345
14511
  const events = await runtime.backend.get(`/api/missions/${encodeURIComponent(missionId)}/events`).catch(() => []);
14346
14512
  const artifacts = await runtime.backend.get(`/api/missions/${encodeURIComponent(missionId)}/artifacts`).catch(() => []);
14347
14513
  const displayId = String(mission.displayId ?? mission.id ?? missionId);
14348
14514
  const title = String(mission.title ?? "(untitled)");
14349
- const objectives = Array.isArray(mission.objectives) ? mission.objectives.map(asRecord) : [];
14515
+ const objectives = Array.isArray(mission.objectives) ? mission.objectives.map(asRecord2) : [];
14350
14516
  const attachmentLines = [];
14351
14517
  await Promise.all(
14352
14518
  objectives.map(async (objective, index) => {
@@ -14354,7 +14520,7 @@ async function loadMissionContext({
14354
14520
  if (typeof objectiveId !== "string" || objectiveId.length === 0) return;
14355
14521
  const attachments = await runtime.backend.get(`/api/objectives/${encodeURIComponent(objectiveId)}/attachments`).catch(() => []);
14356
14522
  for (const attachment of attachments) {
14357
- const record = asRecord(attachment);
14523
+ const record = asRecord2(attachment);
14358
14524
  const filename = String(record.filename ?? "attachment");
14359
14525
  const contentType = record.contentType ? ` (${String(record.contentType)})` : "";
14360
14526
  attachmentLines.push(`- [objective ${index + 1}] ${filename}${contentType}`);
@@ -14381,11 +14547,11 @@ async function loadMissionContext({
14381
14547
  ""
14382
14548
  ] : [],
14383
14549
  "## 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)}`),
14550
+ ...events.filter((event) => !AGENT_HISTORY_EXCLUDED_EVENT_TYPES.has(String(asRecord2(event).type))).slice(-20).map((event) => `- ${asRecord2(event).summary ?? JSON.stringify(event)}`),
14385
14551
  "",
14386
14552
  "## Artifacts",
14387
14553
  ...artifacts.map(
14388
- (artifact) => `- ${asRecord(artifact).label ?? asRecord(artifact).type ?? "artifact"}`
14554
+ (artifact) => `- ${asRecord2(artifact).label ?? asRecord2(artifact).type ?? "artifact"}`
14389
14555
  ),
14390
14556
  "",
14391
14557
  "Use `ovld protocol attach --mission-id <id>` before making changes, update during work, and ALWAYS deliver last."
@@ -14407,7 +14573,7 @@ async function loadProjectResourcesForLaunch({
14407
14573
  }
14408
14574
  }
14409
14575
  });
14410
- const record = asRecord(context);
14576
+ const record = asRecord2(context);
14411
14577
  return Array.isArray(record.projectResources) ? record.projectResources : null;
14412
14578
  } catch {
14413
14579
  return null;
@@ -14524,7 +14690,7 @@ Execution request: ${options.executionRequestId}` : context.launchContext;
14524
14690
  missionLink: { displayId: context.displayId, title: context.title }
14525
14691
  })
14526
14692
  );
14527
- chmodSync3(terminalScriptPath, 448);
14693
+ chmodSync4(terminalScriptPath, 448);
14528
14694
  }
14529
14695
  const execution = resolveLaunchExecution({
14530
14696
  command: command.command,
@@ -15333,7 +15499,7 @@ var init_vcs_sessions = __esm({
15333
15499
  });
15334
15500
 
15335
15501
  // src/vcs.ts
15336
- import { execFileSync as execFileSync5 } from "node:child_process";
15502
+ import { execFileSync as execFileSync6 } from "node:child_process";
15337
15503
  import { createHash as createHash6 } from "node:crypto";
15338
15504
  import {
15339
15505
  existsSync as existsSync20,
@@ -15369,7 +15535,7 @@ function hashWorktreeFile({
15369
15535
  filePath
15370
15536
  }) {
15371
15537
  try {
15372
- return execFileSync5("git", ["hash-object", filePath], {
15538
+ return execFileSync6("git", ["hash-object", filePath], {
15373
15539
  cwd: workingDirectory,
15374
15540
  encoding: "utf8",
15375
15541
  stdio: ["ignore", "pipe", "ignore"]
@@ -15380,7 +15546,7 @@ function hashWorktreeFile({
15380
15546
  }
15381
15547
  function readChangedFiles(workingDirectory) {
15382
15548
  try {
15383
- const output = execFileSync5("git", ["status", "--porcelain"], {
15549
+ const output = execFileSync6("git", ["status", "--porcelain"], {
15384
15550
  cwd: workingDirectory,
15385
15551
  encoding: "utf8",
15386
15552
  stdio: ["ignore", "pipe", "ignore"],
@@ -15521,7 +15687,7 @@ function normalizeAbsolute(filePath) {
15521
15687
  }
15522
15688
  function gitRepoRoot(workingDirectory) {
15523
15689
  try {
15524
- const root = execFileSync5("git", ["rev-parse", "--show-toplevel"], {
15690
+ const root = execFileSync6("git", ["rev-parse", "--show-toplevel"], {
15525
15691
  cwd: workingDirectory,
15526
15692
  encoding: "utf8",
15527
15693
  stdio: ["ignore", "pipe", "ignore"]
@@ -16174,15 +16340,83 @@ var init_resource_observations = __esm({
16174
16340
  }
16175
16341
  });
16176
16342
 
16343
+ // src/runner-identity.ts
16344
+ import { randomUUID } from "node:crypto";
16345
+ import { existsSync as existsSync21, mkdirSync as mkdirSync10, readFileSync as readFileSync16, writeFileSync as writeFileSync9 } from "node:fs";
16346
+ import { hostname as hostname4 } from "node:os";
16347
+ import path25 from "node:path";
16348
+ function envValue(name) {
16349
+ const value = process.env[name]?.trim();
16350
+ return value && value.length > 0 ? value : null;
16351
+ }
16352
+ function runnerInstanceStatePath(dataDir = resolveGlobalDataDir()) {
16353
+ return path25.join(dataDir, RUNNER_INSTANCE_STATE_FILENAME);
16354
+ }
16355
+ function resolveRunnerInstanceId(dataDir = resolveGlobalDataDir()) {
16356
+ const pinned = envValue("OVERLORD_RUNNER_INSTANCE_ID");
16357
+ if (pinned) return pinned;
16358
+ const statePath = runnerInstanceStatePath(dataDir);
16359
+ if (existsSync21(statePath)) {
16360
+ try {
16361
+ const parsed = JSON.parse(readFileSync16(statePath, "utf8"));
16362
+ if (typeof parsed.runnerInstanceId === "string" && parsed.runnerInstanceId.trim()) {
16363
+ return parsed.runnerInstanceId.trim();
16364
+ }
16365
+ } catch {
16366
+ }
16367
+ }
16368
+ const runnerInstanceId = randomUUID();
16369
+ try {
16370
+ mkdirSync10(path25.dirname(statePath), { recursive: true });
16371
+ writeFileSync9(statePath, `${JSON.stringify({ runnerInstanceId }, null, 2)}
16372
+ `, { mode: 384 });
16373
+ } catch {
16374
+ }
16375
+ return runnerInstanceId;
16376
+ }
16377
+ function runnerRegistrationPayload(dataDir = resolveGlobalDataDir()) {
16378
+ const executionTargetId = envValue("OVERLORD_EXECUTION_TARGET_ID");
16379
+ const relationEnv = envValue("OVERLORD_RUNNER_RELATION");
16380
+ if (relationEnv && relationEnv !== "native" && relationEnv !== "adopted") {
16381
+ throw new CliError({
16382
+ message: `OVERLORD_RUNNER_RELATION must be "native" or "adopted" (got "${relationEnv}").`
16383
+ });
16384
+ }
16385
+ if (relationEnv === "adopted" && !executionTargetId) {
16386
+ throw new CliError({
16387
+ message: "OVERLORD_RUNNER_RELATION=adopted requires OVERLORD_EXECUTION_TARGET_ID naming the host execution target this runner adopts."
16388
+ });
16389
+ }
16390
+ return {
16391
+ ...executionTargetId ? { executionTargetId } : {},
16392
+ runnerInstanceId: resolveRunnerInstanceId(dataDir),
16393
+ // Left unset unless declared: the backend knows whether the named target is
16394
+ // this machine's own and derives native/adopted from that.
16395
+ ...relationEnv ? { runnerRelation: relationEnv } : {},
16396
+ runnerLabel: envValue("OVERLORD_DEVICE_LABEL") ?? hostname4(),
16397
+ runnerVersion: getCliVersion()
16398
+ };
16399
+ }
16400
+ var RUNNER_INSTANCE_STATE_FILENAME;
16401
+ var init_runner_identity = __esm({
16402
+ "src/runner-identity.ts"() {
16403
+ "use strict";
16404
+ init_config();
16405
+ init_errors();
16406
+ init_version();
16407
+ RUNNER_INSTANCE_STATE_FILENAME = "runner-instance.json";
16408
+ }
16409
+ });
16410
+
16177
16411
  // src/runner-service.ts
16178
16412
  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";
16413
+ import { chmodSync as chmodSync5, existsSync as existsSync22, mkdirSync as mkdirSync11, readFileSync as readFileSync17, rmSync as rmSync5, writeFileSync as writeFileSync10 } from "node:fs";
16180
16414
  import os4 from "node:os";
16181
- import path25 from "node:path";
16415
+ import path26 from "node:path";
16182
16416
  import { promisify } from "node:util";
16183
16417
  function writeServiceFile(filePath, contents) {
16184
- writeFileSync9(filePath, contents, { mode: 384 });
16185
- chmodSync4(filePath, 384);
16418
+ writeFileSync10(filePath, contents, { mode: 384 });
16419
+ chmodSync5(filePath, 384);
16186
16420
  }
16187
16421
  function emptyRunnerServiceState() {
16188
16422
  return {
@@ -16200,21 +16434,21 @@ function emptyRunnerServiceState() {
16200
16434
  };
16201
16435
  }
16202
16436
  function runnerServiceStatePath(dataDir = resolveGlobalDataDir()) {
16203
- return path25.join(dataDir, RUNNER_SERVICE_STATE_FILENAME);
16437
+ return path26.join(dataDir, RUNNER_SERVICE_STATE_FILENAME);
16204
16438
  }
16205
16439
  function readRunnerServiceState(dataDir = resolveGlobalDataDir()) {
16206
16440
  const filePath = runnerServiceStatePath(dataDir);
16207
- if (!existsSync21(filePath)) return emptyRunnerServiceState();
16441
+ if (!existsSync22(filePath)) return emptyRunnerServiceState();
16208
16442
  try {
16209
- const parsed = JSON.parse(readFileSync16(filePath, "utf8"));
16443
+ const parsed = JSON.parse(readFileSync17(filePath, "utf8"));
16210
16444
  return { ...emptyRunnerServiceState(), ...parsed };
16211
16445
  } catch {
16212
16446
  return emptyRunnerServiceState();
16213
16447
  }
16214
16448
  }
16215
16449
  function writeRunnerServiceState(state, dataDir = resolveGlobalDataDir()) {
16216
- mkdirSync10(dataDir, { recursive: true });
16217
- writeFileSync9(runnerServiceStatePath(dataDir), `${JSON.stringify(state, null, 2)}
16450
+ mkdirSync11(dataDir, { recursive: true });
16451
+ writeFileSync10(runnerServiceStatePath(dataDir), `${JSON.stringify(state, null, 2)}
16218
16452
  `, "utf8");
16219
16453
  }
16220
16454
  function patchRunnerServiceState(patch, dataDir = resolveGlobalDataDir()) {
@@ -16223,13 +16457,13 @@ function patchRunnerServiceState(patch, dataDir = resolveGlobalDataDir()) {
16223
16457
  return next;
16224
16458
  }
16225
16459
  function runnerFocusStatePath(dataDir = resolveGlobalDataDir()) {
16226
- return path25.join(dataDir, RUNNER_FOCUS_STATE_FILENAME);
16460
+ return path26.join(dataDir, RUNNER_FOCUS_STATE_FILENAME);
16227
16461
  }
16228
16462
  function readDesktopFocusState(dataDir = resolveGlobalDataDir()) {
16229
16463
  const filePath = runnerFocusStatePath(dataDir);
16230
- if (!existsSync21(filePath)) return { lastFocusedAt: null };
16464
+ if (!existsSync22(filePath)) return { lastFocusedAt: null };
16231
16465
  try {
16232
- const parsed = JSON.parse(readFileSync16(filePath, "utf8"));
16466
+ const parsed = JSON.parse(readFileSync17(filePath, "utf8"));
16233
16467
  return { lastFocusedAt: parsed.lastFocusedAt ?? null };
16234
16468
  } catch {
16235
16469
  return { lastFocusedAt: null };
@@ -16260,16 +16494,16 @@ function nextRunnerLastError(pollError) {
16260
16494
  function resolveOverlordAppInvocation({
16261
16495
  platform: platform2 = process.platform,
16262
16496
  homedir: homedir2 = os4.homedir(),
16263
- exists = existsSync21
16497
+ exists = existsSync22
16264
16498
  } = {}) {
16265
16499
  if (platform2 !== "darwin") return null;
16266
16500
  const appDirs = [
16267
16501
  "/Applications/Overlord.app",
16268
- path25.join(homedir2, "Applications", "Overlord.app")
16502
+ path26.join(homedir2, "Applications", "Overlord.app")
16269
16503
  ];
16270
16504
  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");
16505
+ const program = path26.join(appDir, "Contents", "MacOS", "Overlord");
16506
+ const script = path26.join(appDir, "Contents", "Resources", "cli", "bin", "ovld.mjs");
16273
16507
  if (exists(program) && exists(script)) {
16274
16508
  return { program, args: [script, "runner", "supervise"], runAsElectronNode: true };
16275
16509
  }
@@ -16281,7 +16515,7 @@ function resolveOvldInvocation(argv = process.argv, execPath = process.execPath)
16281
16515
  if (override) {
16282
16516
  return { program: override, args: ["runner", "supervise"] };
16283
16517
  }
16284
- const scriptPath = argv[1] ? path25.resolve(argv[1]) : "";
16518
+ const scriptPath = argv[1] ? path26.resolve(argv[1]) : "";
16285
16519
  if (process.env.ELECTRON_RUN_AS_NODE) {
16286
16520
  return scriptPath ? { program: execPath, args: [scriptPath, "runner", "supervise"], runAsElectronNode: true } : { program: execPath, args: ["runner", "supervise"], runAsElectronNode: true };
16287
16521
  }
@@ -16314,7 +16548,7 @@ function buildRunnerServiceEnv({
16314
16548
  PATH: process.env.PATH?.trim() || "/usr/local/bin:/usr/bin:/bin"
16315
16549
  };
16316
16550
  const home = overlordHome?.trim() || process.env.OVLD_HOME?.trim();
16317
- if (home) env.OVLD_HOME = path25.resolve(home);
16551
+ if (home) env.OVLD_HOME = path26.resolve(home);
16318
16552
  const token = process.env.OVERLORD_USER_TOKEN?.trim() || process.env.OVLD_USER_TOKEN?.trim();
16319
16553
  if (token) env.OVERLORD_USER_TOKEN = token;
16320
16554
  if (runAsElectronNode || process.env.ELECTRON_RUN_AS_NODE) env.ELECTRON_RUN_AS_NODE = "1";
@@ -16353,9 +16587,9 @@ ${envEntries}
16353
16587
  <key>KeepAlive</key>
16354
16588
  <true/>
16355
16589
  <key>StandardOutPath</key>
16356
- <string>${xmlEscape(path25.join(logDir, "runner-service.out.log"))}</string>
16590
+ <string>${xmlEscape(path26.join(logDir, "runner-service.out.log"))}</string>
16357
16591
  <key>StandardErrorPath</key>
16358
- <string>${xmlEscape(path25.join(logDir, "runner-service.err.log"))}</string>
16592
+ <string>${xmlEscape(path26.join(logDir, "runner-service.err.log"))}</string>
16359
16593
  <key>ProcessType</key>
16360
16594
  <string>Background</string>
16361
16595
  </dict>
@@ -16386,12 +16620,12 @@ WantedBy=default.target
16386
16620
  `;
16387
16621
  }
16388
16622
  function launchAgentsDir() {
16389
- return path25.join(os4.homedir(), "Library", "LaunchAgents");
16623
+ return path26.join(os4.homedir(), "Library", "LaunchAgents");
16390
16624
  }
16391
16625
  function systemdUserDir() {
16392
16626
  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");
16627
+ const base = xdg ? path26.resolve(xdg) : path26.join(os4.homedir(), ".config");
16628
+ return path26.join(base, "systemd", "user");
16395
16629
  }
16396
16630
  async function runCommand(program, args) {
16397
16631
  const { stdout } = await execFileAsync(program, args);
@@ -16420,19 +16654,19 @@ var init_runner_service = __esm({
16420
16654
  kind = "launchd";
16421
16655
  identifier = LAUNCHD_LABEL;
16422
16656
  unitPath() {
16423
- return path25.join(launchAgentsDir(), `${LAUNCHD_LABEL}.plist`);
16657
+ return path26.join(launchAgentsDir(), `${LAUNCHD_LABEL}.plist`);
16424
16658
  }
16425
16659
  render(opts) {
16426
16660
  return renderLaunchdPlist({
16427
16661
  label: LAUNCHD_LABEL,
16428
16662
  invocation: opts.invocation,
16429
16663
  env: opts.env,
16430
- logDir: path25.join(resolveGlobalDataDir(), "logs")
16664
+ logDir: path26.join(resolveGlobalDataDir(), "logs")
16431
16665
  });
16432
16666
  }
16433
16667
  async install(opts) {
16434
- mkdirSync10(launchAgentsDir(), { recursive: true });
16435
- mkdirSync10(path25.join(resolveGlobalDataDir(), "logs"), { recursive: true });
16668
+ mkdirSync11(launchAgentsDir(), { recursive: true });
16669
+ mkdirSync11(path26.join(resolveGlobalDataDir(), "logs"), { recursive: true });
16436
16670
  writeServiceFile(this.unitPath(), this.render(opts));
16437
16671
  if (opts.autoStart) await this.start();
16438
16672
  }
@@ -16462,10 +16696,10 @@ var init_runner_service = __esm({
16462
16696
  await this.stop();
16463
16697
  } catch {
16464
16698
  }
16465
- if (existsSync21(this.unitPath())) rmSync5(this.unitPath());
16699
+ if (existsSync22(this.unitPath())) rmSync5(this.unitPath());
16466
16700
  }
16467
16701
  async status() {
16468
- const installed = existsSync21(this.unitPath());
16702
+ const installed = existsSync22(this.unitPath());
16469
16703
  try {
16470
16704
  const { stdout } = await runCommand("launchctl", ["list"]);
16471
16705
  const line = stdout.split("\n").find((row) => row.includes(LAUNCHD_LABEL));
@@ -16481,13 +16715,13 @@ var init_runner_service = __esm({
16481
16715
  kind = "systemd";
16482
16716
  identifier = `${SYSTEMD_UNIT_NAME}.service`;
16483
16717
  unitPath() {
16484
- return path25.join(systemdUserDir(), `${SYSTEMD_UNIT_NAME}.service`);
16718
+ return path26.join(systemdUserDir(), `${SYSTEMD_UNIT_NAME}.service`);
16485
16719
  }
16486
16720
  render(opts) {
16487
16721
  return renderSystemdUnit(opts);
16488
16722
  }
16489
16723
  async install(opts) {
16490
- mkdirSync10(systemdUserDir(), { recursive: true });
16724
+ mkdirSync11(systemdUserDir(), { recursive: true });
16491
16725
  writeServiceFile(this.unitPath(), this.render(opts));
16492
16726
  await runCommand("systemctl", ["--user", "daemon-reload"]);
16493
16727
  await runCommand("systemctl", ["--user", "enable", this.identifier]);
@@ -16508,14 +16742,14 @@ var init_runner_service = __esm({
16508
16742
  await runCommand("systemctl", ["--user", "disable", this.identifier]);
16509
16743
  } catch {
16510
16744
  }
16511
- if (existsSync21(this.unitPath())) rmSync5(this.unitPath());
16745
+ if (existsSync22(this.unitPath())) rmSync5(this.unitPath());
16512
16746
  try {
16513
16747
  await runCommand("systemctl", ["--user", "daemon-reload"]);
16514
16748
  } catch {
16515
16749
  }
16516
16750
  }
16517
16751
  async status() {
16518
- const installed = existsSync21(this.unitPath());
16752
+ const installed = existsSync22(this.unitPath());
16519
16753
  try {
16520
16754
  const { stdout } = await runCommand("systemctl", ["--user", "is-active", this.identifier]);
16521
16755
  return { installed, running: stdout.trim() === "active" ? "running" : "stopped" };
@@ -16582,14 +16816,14 @@ var init_select_prompt = __esm({
16582
16816
 
16583
16817
  // src/session-key.ts
16584
16818
  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";
16819
+ import { existsSync as existsSync23, mkdirSync as mkdirSync12, readFileSync as readFileSync18, rmSync as rmSync6, writeFileSync as writeFileSync11 } from "node:fs";
16820
+ import path27 from "node:path";
16587
16821
  function sessionKeyCachePath({
16588
16822
  missionId,
16589
16823
  workingDirectory
16590
16824
  }) {
16591
- const key = createHash7("sha256").update(`${path26.resolve(workingDirectory)}\0${missionId}`).digest("hex");
16592
- return path26.join(resolveGlobalDataDir(), "protocol-session-keys", key);
16825
+ const key = createHash7("sha256").update(`${path27.resolve(workingDirectory)}\0${missionId}`).digest("hex");
16826
+ return path27.join(resolveGlobalDataDir(), "protocol-session-keys", key);
16593
16827
  }
16594
16828
  function readCachedSessionKey({
16595
16829
  missionId,
@@ -16597,8 +16831,8 @@ function readCachedSessionKey({
16597
16831
  }) {
16598
16832
  try {
16599
16833
  const filePath = sessionKeyCachePath({ missionId, workingDirectory });
16600
- if (!existsSync22(filePath)) return void 0;
16601
- const raw = JSON.parse(readFileSync17(filePath, "utf8"));
16834
+ if (!existsSync23(filePath)) return void 0;
16835
+ const raw = JSON.parse(readFileSync18(filePath, "utf8"));
16602
16836
  return typeof raw.sessionKey === "string" && raw.sessionKey.trim() ? raw.sessionKey.trim() : void 0;
16603
16837
  } catch {
16604
16838
  return void 0;
@@ -16613,8 +16847,8 @@ function writeCachedSessionKey({
16613
16847
  const trimmed = sessionKey.trim();
16614
16848
  if (!trimmed) return;
16615
16849
  const filePath = sessionKeyCachePath({ missionId, workingDirectory });
16616
- mkdirSync11(path26.dirname(filePath), { recursive: true });
16617
- writeFileSync10(
16850
+ mkdirSync12(path27.dirname(filePath), { recursive: true });
16851
+ writeFileSync11(
16618
16852
  filePath,
16619
16853
  JSON.stringify({ sessionKey: trimmed, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }),
16620
16854
  { mode: 384 }
@@ -16628,7 +16862,7 @@ function clearCachedSessionKey({
16628
16862
  }) {
16629
16863
  try {
16630
16864
  const filePath = sessionKeyCachePath({ missionId, workingDirectory });
16631
- if (existsSync22(filePath)) rmSync6(filePath);
16865
+ if (existsSync23(filePath)) rmSync6(filePath);
16632
16866
  } catch {
16633
16867
  }
16634
16868
  }
@@ -16646,9 +16880,9 @@ __export(commands_exports, {
16646
16880
  runManagementCommand: () => runManagementCommand,
16647
16881
  runProtocolCommand: () => runProtocolCommand
16648
16882
  });
16649
- import { existsSync as existsSync23, readFileSync as readFileSync18 } from "node:fs";
16883
+ import { existsSync as existsSync24, readFileSync as readFileSync19 } from "node:fs";
16650
16884
  import os5 from "node:os";
16651
- import path27 from "node:path";
16885
+ import path28 from "node:path";
16652
16886
  function resourceAccessModeBody(value) {
16653
16887
  if (typeof value !== "string") return {};
16654
16888
  const normalized = value.trim().toLowerCase();
@@ -16665,7 +16899,7 @@ function writeProjectJsonFromResource({
16665
16899
  projectId,
16666
16900
  resource
16667
16901
  }) {
16668
- const record = asRecord2(resource);
16902
+ const record = asRecord3(resource);
16669
16903
  if (typeof record.id !== "string") return;
16670
16904
  if (record.accessMode === "read") return;
16671
16905
  writeProjectJson({
@@ -16694,7 +16928,7 @@ function readChangedFilesFromFlags(flags, stdin) {
16694
16928
  if (typeof fileFlag === "string") {
16695
16929
  const raw = fileFlag === "-" ? stdin ?? "" : (() => {
16696
16930
  try {
16697
- return readFileSync18(fileFlag, "utf8");
16931
+ return readFileSync19(fileFlag, "utf8");
16698
16932
  } catch {
16699
16933
  return "";
16700
16934
  }
@@ -16746,7 +16980,7 @@ function readJsonFlagContent({
16746
16980
  if (typeof filePath === "string") {
16747
16981
  if (fileInputs[fileFlag] !== void 0) return fileInputs[fileFlag];
16748
16982
  try {
16749
- return readFileSync18(filePath, "utf8");
16983
+ return readFileSync19(filePath, "utf8");
16750
16984
  } catch {
16751
16985
  return void 0;
16752
16986
  }
@@ -16969,7 +17203,7 @@ async function resolveTerminalLaunchSettings({
16969
17203
  return { terminalLauncher: null };
16970
17204
  }
16971
17205
  }
16972
- function asRecord2(value) {
17206
+ function asRecord3(value) {
16973
17207
  return value && typeof value === "object" ? value : {};
16974
17208
  }
16975
17209
  function parsePreLaunchCommandsValue(value) {
@@ -17004,32 +17238,32 @@ async function recordBranchPrepared({
17004
17238
  });
17005
17239
  }
17006
17240
  function firstObjectiveId(mission) {
17007
- const objectives = asRecord2(mission).objectives;
17241
+ const objectives = asRecord3(mission).objectives;
17008
17242
  if (!Array.isArray(objectives)) return void 0;
17009
17243
  const first = objectives[0];
17010
- const id = asRecord2(first).id;
17244
+ const id = asRecord3(first).id;
17011
17245
  return typeof id === "string" ? id : void 0;
17012
17246
  }
17013
17247
  function launchableObjectiveId(mission) {
17014
- const objectives = asRecord2(mission).objectives;
17248
+ const objectives = asRecord3(mission).objectives;
17015
17249
  if (!Array.isArray(objectives)) return void 0;
17016
17250
  const launchableStates = ["executing", "submitted", "launching", "draft"];
17017
17251
  for (const state of launchableStates) {
17018
- const match = objectives.find((objective) => asRecord2(objective).state === state);
17019
- const id = asRecord2(match).id;
17252
+ const match = objectives.find((objective) => asRecord3(objective).state === state);
17253
+ const id = asRecord3(match).id;
17020
17254
  if (typeof id === "string") return id;
17021
17255
  }
17022
17256
  return firstObjectiveId(mission);
17023
17257
  }
17024
17258
  function objectiveAssignedAgent(mission, objectiveId) {
17025
- const objectives = asRecord2(mission).objectives;
17259
+ const objectives = asRecord3(mission).objectives;
17026
17260
  if (!Array.isArray(objectives)) return void 0;
17027
- const match = objectives.find((objective) => asRecord2(objective).id === objectiveId);
17028
- const agent = asRecord2(match).assignedAgent;
17261
+ const match = objectives.find((objective) => asRecord3(objective).id === objectiveId);
17262
+ const agent = asRecord3(match).assignedAgent;
17029
17263
  return typeof agent === "string" && agent.trim() ? agent.trim() : void 0;
17030
17264
  }
17031
17265
  function missionDisplayId(mission) {
17032
- const record = asRecord2(mission);
17266
+ const record = asRecord3(mission);
17033
17267
  return typeof record.displayId === "string" ? record.displayId : typeof record.id === "string" ? record.id : "unknown";
17034
17268
  }
17035
17269
  async function resolveProtocolFileInputs({
@@ -17050,7 +17284,7 @@ async function resolveProtocolFileInputs({
17050
17284
  } else if (process.stdin.isTTY) {
17051
17285
  stdinContent = "";
17052
17286
  } else {
17053
- stdinContent = readFileSync18(0, "utf8");
17287
+ stdinContent = readFileSync19(0, "utf8");
17054
17288
  }
17055
17289
  return stdinContent;
17056
17290
  };
@@ -17064,7 +17298,7 @@ async function resolveProtocolFileInputs({
17064
17298
  fileInputs[flagName] = content;
17065
17299
  stdinPayload = content;
17066
17300
  } else {
17067
- fileInputs[flagName] = readFileSync18(filePath, "utf8");
17301
+ fileInputs[flagName] = readFileSync19(filePath, "utf8");
17068
17302
  }
17069
17303
  }
17070
17304
  if (stdinPayload === void 0 && stdin !== void 0 && Object.keys(fileInputs).length === 0) {
@@ -17076,7 +17310,7 @@ async function discoverProjectId(runtime, explicit) {
17076
17310
  if (explicit) return explicit;
17077
17311
  const projects = await listAccessibleProjects({ backend: runtime.backend });
17078
17312
  const first = projects[0];
17079
- const id = asRecord2(first).id;
17313
+ const id = asRecord3(first).id;
17080
17314
  if (typeof id !== "string") {
17081
17315
  throw new CliError({ message: "No project found. Create one with `ovld create-project`." });
17082
17316
  }
@@ -17107,7 +17341,7 @@ async function runProtocolCommand({
17107
17341
  });
17108
17342
  if (subcommand === "record-touched") {
17109
17343
  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"));
17344
+ const rawPayload = stdin ?? (process.stdin.isTTY ? "" : readFileSync19(0, "utf8"));
17111
17345
  const result2 = recordTouchedFromPayload({
17112
17346
  rawPayload,
17113
17347
  missionOverride,
@@ -17218,7 +17452,7 @@ async function runProtocolCommand({
17218
17452
  resetTouchedFiles({ workingDirectory, missionId });
17219
17453
  resetRationaleNotes({ workingDirectory, missionId });
17220
17454
  }
17221
- const resultRecord = asRecord2(result);
17455
+ const resultRecord = asRecord3(result);
17222
17456
  if (typeof resultRecord.sessionKey === "string") {
17223
17457
  printKeyValue({ SESSION_KEY: resultRecord.sessionKey });
17224
17458
  if (missionId) {
@@ -17233,7 +17467,7 @@ async function runProtocolCommand({
17233
17467
  }
17234
17468
  }
17235
17469
  if (subcommand === "attach" || subcommand === "connect" || subcommand === "resume-follow-up") {
17236
- const missionRecord = asRecord2(resultRecord.mission);
17470
+ const missionRecord = asRecord3(resultRecord.mission);
17237
17471
  const displayId = typeof missionRecord.displayId === "string" && missionRecord.displayId.trim() || typeof missionId === "string" && missionId.trim() || typeof resultRecord.missionId === "string" && resultRecord.missionId.trim() || "";
17238
17472
  const title = typeof missionRecord.title === "string" ? missionRecord.title : void 0;
17239
17473
  const pointerMissionId = typeof missionRecord.id === "string" && missionRecord.id.trim() || typeof resultRecord.missionId === "string" && resultRecord.missionId.trim() || displayId;
@@ -17253,8 +17487,8 @@ async function runProtocolCommand({
17253
17487
  clearCachedSessionKey({ missionId, workingDirectory });
17254
17488
  removeActiveSession({ workingDirectory, missionId });
17255
17489
  clearActiveMissionPointer(workingDirectory);
17256
- const connectorInstallsEditHook = existsSync23(path27.join(os5.homedir(), ".claude")) || existsSync23(
17257
- path27.join(
17490
+ const connectorInstallsEditHook = existsSync24(path28.join(os5.homedir(), ".claude")) || existsSync24(
17491
+ path28.join(
17258
17492
  os5.homedir(),
17259
17493
  ".cursor",
17260
17494
  "plugins",
@@ -17303,7 +17537,7 @@ async function runProtocolCommand({
17303
17537
  if (subcommand === "attachment-list" && Array.isArray(result)) {
17304
17538
  const baseUrl = runtime.backend.baseUrl;
17305
17539
  const enhanced = result.map((entry) => {
17306
- const rec = asRecord2(entry);
17540
+ const rec = asRecord3(entry);
17307
17541
  const relUrl = rec.url;
17308
17542
  return typeof relUrl === "string" && relUrl.startsWith("/") ? { ...rec, url: `${baseUrl}${relUrl}` } : rec;
17309
17543
  });
@@ -17328,7 +17562,7 @@ async function runManagementCommand({
17328
17562
  path: "/api/projects",
17329
17563
  body: { name }
17330
17564
  });
17331
- const projectId = asRecord2(project).id;
17565
+ const projectId = asRecord3(project).id;
17332
17566
  if (!flagBoolean(parsed.flags, "--no-directory") && typeof projectId === "string") {
17333
17567
  const directory = flagValue(parsed.flags, "--directory") ?? process.cwd();
17334
17568
  const resource = await runtime.backend.post({
@@ -17343,7 +17577,7 @@ async function runManagementCommand({
17343
17577
  if (json) printJson({ project });
17344
17578
  else
17345
17579
  console.log(
17346
- `Created project ${asRecord2(project).name ?? name} (${projectId ?? "unknown"})`
17580
+ `Created project ${asRecord3(project).name ?? name} (${projectId ?? "unknown"})`
17347
17581
  );
17348
17582
  return;
17349
17583
  }
@@ -17354,7 +17588,7 @@ async function runManagementCommand({
17354
17588
  case "add-cwd": {
17355
17589
  const directory = flagValue(parsed.flags, "--directory") ?? process.cwd();
17356
17590
  const existingProjectJson = readProjectJsonLink(
17357
- path27.join(directory, ".overlord", "project.json")
17591
+ path28.join(directory, ".overlord", "project.json")
17358
17592
  );
17359
17593
  const resourceKey = flagValue(parsed.flags, "--key") ?? existingProjectJson?.resourceKey;
17360
17594
  let projectId = flagValue(parsed.flags, "--project-id");
@@ -17420,7 +17654,7 @@ async function runManagementCommand({
17420
17654
  path: "/api/protocol/register-target",
17421
17655
  body: { args: rest, positional: parsed.positional, flags: protocolFlags, fileInputs: {} }
17422
17656
  });
17423
- const record = asRecord2(result);
17657
+ const record = asRecord3(result);
17424
17658
  if (record.status === "workspace_selection_required") {
17425
17659
  if (json) {
17426
17660
  printJson({ result });
@@ -17430,7 +17664,7 @@ async function runManagementCommand({
17430
17664
  "You belong to more than one workspace. Re-run with --workspace-id set to one of:"
17431
17665
  );
17432
17666
  for (const entry of workspaces) {
17433
- const ws = asRecord2(entry);
17667
+ const ws = asRecord3(entry);
17434
17668
  console.log(` - ${ws.name ?? ws.id} (${ws.slug ?? ws.id})`);
17435
17669
  }
17436
17670
  }
@@ -17439,8 +17673,8 @@ async function runManagementCommand({
17439
17673
  if (json) {
17440
17674
  printJson({ result });
17441
17675
  } else {
17442
- const target = asRecord2(record.executionTarget);
17443
- const ws = asRecord2(record.workspace);
17676
+ const target = asRecord3(record.executionTarget);
17677
+ const ws = asRecord3(record.workspace);
17444
17678
  console.log(
17445
17679
  `Registered execution target ${target.label ?? name ?? ""} (${target.executionTargetId ?? "unknown"}) in workspace ${ws.name ?? ws.id ?? ""}`
17446
17680
  );
@@ -17475,7 +17709,7 @@ async function runManagementCommand({
17475
17709
  }
17476
17710
  });
17477
17711
  if (objectivesJson) {
17478
- const missionObjectives = asRecord2(mission).objectives;
17712
+ const missionObjectives = asRecord3(mission).objectives;
17479
17713
  if (Array.isArray(missionObjectives) && missionObjectives.length !== objectives.length) {
17480
17714
  throw new CliError({
17481
17715
  message: `Backend created ${missionObjectives.length} objective(s), expected ${objectives.length}`
@@ -17543,10 +17777,10 @@ async function runManagementCommand({
17543
17777
  const executionTargetId = await resolvePreferredExecutionTargetId({
17544
17778
  backend: scopedRuntime.backend
17545
17779
  });
17546
- const missionProjectId = asRecord2(mission).projectId;
17780
+ const missionProjectId = asRecord3(mission).projectId;
17547
17781
  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)
17782
+ preLaunchCommands: parsePreLaunchCommandsValue(asRecord3(project).preLaunchCommands),
17783
+ launchEnvVars: parseLaunchEnvVarsValue(asRecord3(project).launchEnvVars)
17550
17784
  })).catch(() => ({
17551
17785
  preLaunchCommands: [],
17552
17786
  launchEnvVars: {}
@@ -17621,7 +17855,7 @@ async function runManagementCommand({
17621
17855
  if (json) printJson({ missions });
17622
17856
  else {
17623
17857
  for (const mission of missions) {
17624
- const record = asRecord2(mission);
17858
+ const record = asRecord3(mission);
17625
17859
  console.log(
17626
17860
  `${record.displayId ?? record.id} ${record.statusType ?? ""} ${record.title ?? ""}`
17627
17861
  );
@@ -17644,13 +17878,13 @@ async function runManagementCommand({
17644
17878
  rationales: `/api/missions/${encodeURIComponent(missionId)}/file-changes`,
17645
17879
  deliveries: `/api/missions/${encodeURIComponent(missionId)}/deliveries`
17646
17880
  };
17647
- const path28 = sub ? pathBySub[sub] : void 0;
17648
- if (!path28) {
17881
+ const path29 = sub ? pathBySub[sub] : void 0;
17882
+ if (!path29) {
17649
17883
  throw new CliError({
17650
17884
  message: "Usage: ovld mission context|events|deliveries|artifacts|rationales <missionId> [--json]"
17651
17885
  });
17652
17886
  }
17653
- const result = await runtime.backend.get(path28);
17887
+ const result = await runtime.backend.get(path29);
17654
17888
  if (json || sub === "context") printJson(result);
17655
17889
  else if (Array.isArray(result)) for (const row of result) console.log(JSON.stringify(row));
17656
17890
  else printJson(result);
@@ -17673,6 +17907,10 @@ async function runManagementCommand({
17673
17907
  throw new CliError({ message: `Unknown command: ${command}` });
17674
17908
  }
17675
17909
  }
17910
+ function isNoExecutionTargetRegisteredError(error) {
17911
+ const message = error instanceof Error ? error.message : String(error);
17912
+ return message.includes("(no_execution_target_registered)");
17913
+ }
17676
17914
  async function runRunnerCommand({
17677
17915
  runtime,
17678
17916
  parsed,
@@ -17694,7 +17932,7 @@ async function runRunnerCommand({
17694
17932
  }
17695
17933
  });
17696
17934
  if (json) printJson(result);
17697
- else console.log(`Cleared ${asRecord2(result).cleared ?? 0} execution request(s).`);
17935
+ else console.log(`Cleared ${asRecord3(result).cleared ?? 0} execution request(s).`);
17698
17936
  return;
17699
17937
  }
17700
17938
  if (sub === "service") {
@@ -17707,17 +17945,32 @@ async function runRunnerCommand({
17707
17945
  });
17708
17946
  }
17709
17947
  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()
17948
+ let claim;
17949
+ try {
17950
+ claim = await runtime.backend.post({
17951
+ path: "/api/runner/claim",
17952
+ body: {
17953
+ projectId: flagValue(parsed.flags, "--project-id"),
17954
+ ...clientDeviceIdentity(),
17955
+ // Contract v40: the claim poll doubles as this runner instance's
17956
+ // heartbeat, so local target liveness reflects a runner that can
17957
+ // actually take work rather than any CLI traffic from the machine.
17958
+ ...runnerRegistrationPayload()
17959
+ }
17960
+ });
17961
+ } catch (error) {
17962
+ if (isNoExecutionTargetRegisteredError(error)) {
17963
+ throw new CliError({
17964
+ message: `${error instanceof Error ? error.message : String(error)}
17965
+ The runner will not register a target for you \u2014 declare this machine first, then start it again.`
17966
+ });
17715
17967
  }
17716
- });
17717
- const request = asRecord2(claim).request;
17718
- const longPoll = asRecord2(claim).longPoll === true;
17968
+ throw error;
17969
+ }
17970
+ const request = asRecord3(claim).request;
17971
+ const longPoll = asRecord3(claim).longPoll === true;
17719
17972
  if (!request) return { launched: false, longPoll };
17720
- const requestRecord = asRecord2(request);
17973
+ const requestRecord = asRecord3(request);
17721
17974
  const requestId = String(requestRecord.id);
17722
17975
  const projectId = String(requestRecord.projectId ?? "");
17723
17976
  const executionTargetId = typeof requestRecord.executionTargetId === "string" ? requestRecord.executionTargetId.trim() : "";
@@ -17757,7 +18010,7 @@ async function runRunnerCommand({
17757
18010
  message: `Execution request ${requestId} has no agent; the objective must specify one before it can be launched.`
17758
18011
  });
17759
18012
  }
17760
- const launchConfig = asRecord2(requestRecord.launchConfig);
18013
+ const launchConfig = asRecord3(requestRecord.launchConfig);
17761
18014
  const terminal = await resolveTerminalLaunchSettings({ runtime, flags: parsed.flags });
17762
18015
  const missionId = String(requestRecord.missionId);
17763
18016
  const dryRun = flagBoolean(parsed.flags, "--dry-run");
@@ -17848,6 +18101,7 @@ async function runRunnerSupervisor({
17848
18101
  try {
17849
18102
  result = await runOnce();
17850
18103
  } catch (error) {
18104
+ if (isNoExecutionTargetRegisteredError(error)) throw error;
17851
18105
  lastError = error instanceof Error ? error.message : String(error);
17852
18106
  }
17853
18107
  const state = readRunnerServiceState();
@@ -17998,6 +18252,7 @@ var init_commands = __esm({
17998
18252
  init_protocol_help();
17999
18253
  init_record_touched();
18000
18254
  init_resource_observations();
18255
+ init_runner_identity();
18001
18256
  init_runner_service();
18002
18257
  init_select_prompt();
18003
18258
  init_session_key();