@openscout/scout 0.2.60 → 0.2.62

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.
@@ -56,6 +56,9 @@ function resolvedPairingConfig() {
56
56
  };
57
57
  }
58
58
 
59
+ // ../../apps/desktop/src/core/pairing/supervisor.ts
60
+ import { spawn as spawn4 } from "child_process";
61
+
59
62
  // ../../node_modules/.bun/uqr@0.1.3/node_modules/uqr/dist/index.mjs
60
63
  var QrCodeDataType = /* @__PURE__ */ ((QrCodeDataType2) => {
61
64
  QrCodeDataType2[QrCodeDataType2["Border"] = -1] = "Border";
@@ -685,7 +688,7 @@ function renderQRCode(payload) {
685
688
  // ../../apps/desktop/src/core/pairing/runtime/relay-runtime.ts
686
689
  import { execSync } from "child_process";
687
690
  import { existsSync as existsSync2, mkdirSync as mkdirSync3, readdirSync } from "fs";
688
- import { homedir as homedir2 } from "os";
691
+ import { homedir as homedir2, networkInterfaces } from "os";
689
692
  import { join } from "path";
690
693
 
691
694
  // ../../apps/desktop/src/core/pairing/runtime/log.ts
@@ -716,6 +719,7 @@ function startRelay(port, options = {}) {
716
719
  const roomByBridgeKey = new Map;
717
720
  const server = Bun.serve({
718
721
  port,
722
+ hostname: "0.0.0.0",
719
723
  ...options.tls ? {
720
724
  tls: {
721
725
  cert: Bun.file(options.tls.cert),
@@ -974,24 +978,42 @@ function readTailscaleStatus() {
974
978
  return null;
975
979
  }
976
980
  }
977
- function resolveRelayEndpointForTailscaleStatus(port, tailscale) {
981
+ function resolveRelayEndpointForTailscaleStatus(port, tailscale, options = {}) {
978
982
  const backendState = tailscale?.backendState?.trim().toLowerCase() ?? "";
979
983
  const hostname = tailscale?.dnsName ?? null;
980
984
  const tailscaleRunning = backendState === "running" && tailscale?.online !== false && Boolean(hostname);
981
- const tls = resolveTls(tailscaleRunning ? hostname : null);
982
- if (tailscaleRunning && hostname && tls) {
985
+ const tls = tailscaleRunning ? options.tls !== undefined ? options.tls : resolveTls(hostname) : null;
986
+ const scheme = tls ? "wss" : "ws";
987
+ const connectUrl = `${scheme}://127.0.0.1:${port}`;
988
+ const localAddress = options.localAddress !== undefined ? normalizedOptionalAddress(options.localAddress) : findLocalNetworkAddress();
989
+ const localRelayUrl = localAddress ? `${scheme}://${localAddress}:${port}` : null;
990
+ const tailnetRelayUrl = tailscaleRunning && hostname ? `${scheme}://${hostname}:${port}` : null;
991
+ const fallbackRelayUrls = tailnetRelayUrl && localRelayUrl ? [tailnetRelayUrl] : [];
992
+ if (localRelayUrl) {
983
993
  return {
984
- relayUrl: `wss://${hostname}:${port}`,
994
+ relayUrl: localRelayUrl,
995
+ connectUrl,
996
+ fallbackRelayUrls,
997
+ options: tls ? { tls } : {}
998
+ };
999
+ }
1000
+ if (tailnetRelayUrl && tls) {
1001
+ return {
1002
+ relayUrl: tailnetRelayUrl,
1003
+ connectUrl,
1004
+ fallbackRelayUrls: [],
985
1005
  options: { tls }
986
1006
  };
987
1007
  }
988
- if (tailscaleRunning && hostname) {
1008
+ if (tailnetRelayUrl) {
989
1009
  pairingLog.warn("relay", "tailscale is running without TLS; falling back to insecure websocket relay", {
990
1010
  hostname,
991
1011
  port
992
1012
  });
993
1013
  return {
994
- relayUrl: `ws://${hostname}:${port}`,
1014
+ relayUrl: tailnetRelayUrl,
1015
+ connectUrl,
1016
+ fallbackRelayUrls: [],
995
1017
  options: {}
996
1018
  };
997
1019
  }
@@ -1004,7 +1026,9 @@ function resolveRelayEndpointForTailscaleStatus(port, tailscale) {
1004
1026
  });
1005
1027
  }
1006
1028
  return {
1007
- relayUrl: `ws://127.0.0.1:${port}`,
1029
+ relayUrl: connectUrl,
1030
+ connectUrl,
1031
+ fallbackRelayUrls: [],
1008
1032
  options: {}
1009
1033
  };
1010
1034
  }
@@ -1057,16 +1081,87 @@ function resolveRelayEndpoint(port) {
1057
1081
  }
1058
1082
  function startManagedRelay(port = 7889) {
1059
1083
  const endpoint = resolveRelayEndpoint(port);
1060
- pairingLog.info("relay", "starting managed relay", { relay: endpoint.relayUrl, port });
1084
+ pairingLog.info("relay", "starting managed relay", {
1085
+ relay: endpoint.relayUrl,
1086
+ connectUrl: endpoint.connectUrl,
1087
+ fallbackRelayUrls: endpoint.fallbackRelayUrls,
1088
+ port
1089
+ });
1061
1090
  const relay = startRelay(port, endpoint.options);
1062
1091
  return {
1063
1092
  relayUrl: endpoint.relayUrl,
1093
+ connectUrl: endpoint.connectUrl,
1094
+ fallbackRelayUrls: endpoint.fallbackRelayUrls,
1064
1095
  stop() {
1065
1096
  pairingLog.info("relay", "stopping managed relay", { relay: endpoint.relayUrl, port });
1066
1097
  relay.stop();
1067
1098
  }
1068
1099
  };
1069
1100
  }
1101
+ function normalizedOptionalAddress(address) {
1102
+ const trimmed = address?.trim();
1103
+ return trimmed ? trimmed : null;
1104
+ }
1105
+ function findLocalNetworkAddress() {
1106
+ const candidates = [];
1107
+ const interfaces = networkInterfaces();
1108
+ for (const [name, entries] of Object.entries(interfaces)) {
1109
+ for (const entry of entries ?? []) {
1110
+ if (entry.internal || entry.family !== "IPv4") {
1111
+ continue;
1112
+ }
1113
+ if (!isPrivateIPv4(entry.address) || isLinkLocalIPv4(entry.address) || isTailscaleIPv4(entry.address)) {
1114
+ continue;
1115
+ }
1116
+ candidates.push({ name, address: entry.address });
1117
+ }
1118
+ }
1119
+ candidates.sort((left, right) => {
1120
+ const leftScore = localInterfaceScore(left.name);
1121
+ const rightScore = localInterfaceScore(right.name);
1122
+ if (leftScore !== rightScore) {
1123
+ return leftScore - rightScore;
1124
+ }
1125
+ return left.address.localeCompare(right.address);
1126
+ });
1127
+ return candidates[0]?.address ?? null;
1128
+ }
1129
+ function localInterfaceScore(name) {
1130
+ if (/^en\d+$/i.test(name)) {
1131
+ return 0;
1132
+ }
1133
+ if (/^bridge\d*$/i.test(name)) {
1134
+ return 2;
1135
+ }
1136
+ return 1;
1137
+ }
1138
+ function isPrivateIPv4(address) {
1139
+ const octets = parseIPv4(address);
1140
+ if (!octets) {
1141
+ return false;
1142
+ }
1143
+ const [first, second] = octets;
1144
+ return first === 10 || first === 172 && second >= 16 && second <= 31 || first === 192 && second === 168;
1145
+ }
1146
+ function isLinkLocalIPv4(address) {
1147
+ const octets = parseIPv4(address);
1148
+ return Boolean(octets && octets[0] === 169 && octets[1] === 254);
1149
+ }
1150
+ function isTailscaleIPv4(address) {
1151
+ const octets = parseIPv4(address);
1152
+ return Boolean(octets && octets[0] === 100 && octets[1] >= 64 && octets[1] <= 127);
1153
+ }
1154
+ function parseIPv4(address) {
1155
+ const octets = address.split(".");
1156
+ if (octets.length !== 4) {
1157
+ return null;
1158
+ }
1159
+ const numbers = octets.map((octet) => Number(octet));
1160
+ if (numbers.some((value) => !Number.isInteger(value) || value < 0 || value > 255)) {
1161
+ return null;
1162
+ }
1163
+ return numbers;
1164
+ }
1070
1165
 
1071
1166
  // ../../apps/desktop/src/core/pairing/runtime/runtime-state.ts
1072
1167
  import { existsSync as existsSync4, mkdirSync as mkdirSync5, readFileSync as readFileSync3, renameSync, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
@@ -3152,15 +3247,30 @@ function isTrustedPeer(publicKeyHex) {
3152
3247
  }
3153
3248
  var QR_VERSION = 1;
3154
3249
  var QR_EXPIRY_MS = 5 * 60 * 1000;
3155
- function createQRPayload(bridgePublicKey, relayUrl) {
3250
+ function createQRPayload(bridgePublicKey, relayUrl, fallbackRelayUrls = []) {
3251
+ const fallbackRelays = normalizedRelayUrls(fallbackRelayUrls, relayUrl);
3156
3252
  return {
3157
3253
  v: QR_VERSION,
3158
3254
  relay: relayUrl,
3255
+ ...fallbackRelays.length > 0 ? { fallbackRelays } : {},
3159
3256
  room: crypto.randomUUID(),
3160
3257
  publicKey: bytesToHex2(bridgePublicKey),
3161
3258
  expiresAt: Date.now() + QR_EXPIRY_MS
3162
3259
  };
3163
3260
  }
3261
+ function normalizedRelayUrls(urls, primaryRelayUrl) {
3262
+ const seen = new Set([primaryRelayUrl.trim()]);
3263
+ const normalized = [];
3264
+ for (const url of urls) {
3265
+ const trimmed = url.trim();
3266
+ if (!trimmed || seen.has(trimmed)) {
3267
+ continue;
3268
+ }
3269
+ seen.add(trimmed);
3270
+ normalized.push(trimmed);
3271
+ }
3272
+ return normalized;
3273
+ }
3164
3274
  function bytesToHex2(bytes) {
3165
3275
  return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
3166
3276
  }
@@ -3394,7 +3504,7 @@ function writeJsonAtomically(filePath, value) {
3394
3504
  }
3395
3505
 
3396
3506
  // ../../apps/desktop/src/core/pairing/runtime/runtime.ts
3397
- import { homedir as homedir18 } from "os";
3507
+ import { homedir as homedir19 } from "os";
3398
3508
  // ../agent-sessions/src/protocol/adapter.ts
3399
3509
  class BaseAdapter {
3400
3510
  config;
@@ -4026,6 +4136,15 @@ function stringifyUnknown(value) {
4026
4136
  return String(value);
4027
4137
  }
4028
4138
  }
4139
+ function isRecord(value) {
4140
+ return !!value && typeof value === "object" && !Array.isArray(value);
4141
+ }
4142
+ function maybeString(value) {
4143
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
4144
+ }
4145
+ function maybeNumber(value) {
4146
+ return typeof value === "number" && Number.isFinite(value) ? value : undefined;
4147
+ }
4029
4148
  function renderToolResultContent(content) {
4030
4149
  if (typeof content === "string") {
4031
4150
  return content;
@@ -4081,6 +4200,7 @@ class ClaudeCodeHistoryParser {
4081
4200
  blockById = new Map;
4082
4201
  activeStreamBlocks = new Map;
4083
4202
  sawStreamTextThisTurn = false;
4203
+ assistantUsageByMessageId = new Map;
4084
4204
  constructor(session, baseTimestampMs) {
4085
4205
  this.session = session;
4086
4206
  this.baseTimestampMs = baseTimestampMs;
@@ -4090,6 +4210,7 @@ class ClaudeCodeHistoryParser {
4090
4210
  let parsedLineCount = 0;
4091
4211
  let skippedLineCount = 0;
4092
4212
  let lineCount = 0;
4213
+ let lastCapturedAt = this.baseTimestampMs;
4093
4214
  for (let index = 0;index < lines.length; index += 1) {
4094
4215
  const rawLine = lines[index];
4095
4216
  const trimmed = rawLine.trim();
@@ -4110,12 +4231,19 @@ class ClaudeCodeHistoryParser {
4110
4231
  continue;
4111
4232
  }
4112
4233
  const capturedAt = extractRecordTimestamp(record) ?? this.baseTimestampMs + index;
4234
+ lastCapturedAt = capturedAt;
4113
4235
  if (this.handleRecord(record, capturedAt)) {
4114
4236
  parsedLineCount += 1;
4115
4237
  } else {
4116
4238
  skippedLineCount += 1;
4117
4239
  }
4118
4240
  }
4241
+ if (this.persistObserveUsageMetadata()) {
4242
+ this.emitEvent(lastCapturedAt, {
4243
+ event: "session:update",
4244
+ session: { ...this.session }
4245
+ });
4246
+ }
4119
4247
  return {
4120
4248
  events: this.events,
4121
4249
  lineCount,
@@ -4124,6 +4252,7 @@ class ClaudeCodeHistoryParser {
4124
4252
  };
4125
4253
  }
4126
4254
  handleRecord(record, capturedAt) {
4255
+ this.captureRecordMetadata(record);
4127
4256
  const type = typeof record.type === "string" ? record.type : null;
4128
4257
  if (!type) {
4129
4258
  return false;
@@ -4133,7 +4262,7 @@ class ClaudeCodeHistoryParser {
4133
4262
  this.handleSystem(record, capturedAt);
4134
4263
  return true;
4135
4264
  case "user":
4136
- this.startTurn(capturedAt);
4265
+ this.handleUser(record, capturedAt);
4137
4266
  return true;
4138
4267
  case "assistant":
4139
4268
  this.handleAssistant(record, capturedAt);
@@ -4157,6 +4286,130 @@ class ClaudeCodeHistoryParser {
4157
4286
  return false;
4158
4287
  }
4159
4288
  }
4289
+ captureRecordMetadata(record) {
4290
+ const runtime = this.ensureObserveMetaRecord("observeRuntime");
4291
+ this.assignObserveString(runtime, "entrypoint", record.entrypoint);
4292
+ this.assignObserveString(runtime, "cliVersion", record.version);
4293
+ this.assignObserveString(runtime, "gitBranch", record.gitBranch);
4294
+ this.assignObserveString(runtime, "permissionMode", record.permissionMode);
4295
+ this.assignObserveString(runtime, "userType", record.userType);
4296
+ const recordCwd = maybeString(record.cwd);
4297
+ if (recordCwd && !this.session.cwd) {
4298
+ this.session.cwd = recordCwd;
4299
+ }
4300
+ const message = isRecord(record.message) ? record.message : null;
4301
+ const model = maybeString(message?.model);
4302
+ if (model && !this.session.model) {
4303
+ this.session.model = model;
4304
+ }
4305
+ const usage = this.readClaudeUsageEntry(record);
4306
+ if (!usage) {
4307
+ return;
4308
+ }
4309
+ const messageId = maybeString(message?.id) ?? maybeString(record.requestId) ?? maybeString(record.uuid);
4310
+ if (!messageId) {
4311
+ return;
4312
+ }
4313
+ this.assistantUsageByMessageId.set(messageId, usage);
4314
+ }
4315
+ readClaudeUsageEntry(record) {
4316
+ const type = maybeString(record.type);
4317
+ const message = isRecord(record.message) ? record.message : null;
4318
+ const role = maybeString(message?.role);
4319
+ if (type !== "assistant" && role !== "assistant") {
4320
+ return null;
4321
+ }
4322
+ const usage = isRecord(message?.usage) ? message.usage : null;
4323
+ const serverToolUse = isRecord(usage?.server_tool_use) ? usage.server_tool_use : null;
4324
+ const entry = {
4325
+ inputTokens: maybeNumber(usage?.input_tokens) ?? 0,
4326
+ outputTokens: maybeNumber(usage?.output_tokens) ?? 0,
4327
+ cacheReadInputTokens: maybeNumber(usage?.cache_read_input_tokens) ?? 0,
4328
+ cacheCreationInputTokens: maybeNumber(usage?.cache_creation_input_tokens) ?? 0,
4329
+ webSearchRequests: maybeNumber(serverToolUse?.web_search_requests) ?? 0,
4330
+ webFetchRequests: maybeNumber(serverToolUse?.web_fetch_requests) ?? 0,
4331
+ ...maybeString(message?.service_tier) ? { serviceTier: maybeString(message?.service_tier) } : {},
4332
+ ...maybeString(message?.speed) ? { speed: maybeString(message?.speed) } : {}
4333
+ };
4334
+ const hasUsage = entry.inputTokens > 0 || entry.outputTokens > 0 || entry.cacheReadInputTokens > 0 || entry.cacheCreationInputTokens > 0 || entry.webSearchRequests > 0 || entry.webFetchRequests > 0 || Boolean(entry.serviceTier) || Boolean(entry.speed);
4335
+ return hasUsage ? entry : null;
4336
+ }
4337
+ persistObserveUsageMetadata() {
4338
+ if (this.assistantUsageByMessageId.size === 0) {
4339
+ return false;
4340
+ }
4341
+ const usage = this.ensureObserveMetaRecord("observeUsage");
4342
+ let inputTokens = 0;
4343
+ let outputTokens = 0;
4344
+ let cacheReadInputTokens = 0;
4345
+ let cacheCreationInputTokens = 0;
4346
+ let webSearchRequests = 0;
4347
+ let webFetchRequests = 0;
4348
+ let serviceTier;
4349
+ let speed;
4350
+ for (const entry of this.assistantUsageByMessageId.values()) {
4351
+ inputTokens += entry.inputTokens;
4352
+ outputTokens += entry.outputTokens;
4353
+ cacheReadInputTokens += entry.cacheReadInputTokens;
4354
+ cacheCreationInputTokens += entry.cacheCreationInputTokens;
4355
+ webSearchRequests += entry.webSearchRequests;
4356
+ webFetchRequests += entry.webFetchRequests;
4357
+ if (entry.serviceTier) {
4358
+ serviceTier = entry.serviceTier;
4359
+ }
4360
+ if (entry.speed) {
4361
+ speed = entry.speed;
4362
+ }
4363
+ }
4364
+ let changed = false;
4365
+ const assignNumber = (key, value) => {
4366
+ if (usage[key] !== value) {
4367
+ usage[key] = value;
4368
+ changed = true;
4369
+ }
4370
+ };
4371
+ const assignString = (key, value) => {
4372
+ if (usage[key] !== value) {
4373
+ usage[key] = value;
4374
+ changed = true;
4375
+ }
4376
+ };
4377
+ assignNumber("assistantMessages", this.assistantUsageByMessageId.size);
4378
+ if (inputTokens > 0)
4379
+ assignNumber("inputTokens", inputTokens);
4380
+ if (outputTokens > 0)
4381
+ assignNumber("outputTokens", outputTokens);
4382
+ if (cacheReadInputTokens > 0)
4383
+ assignNumber("cacheReadInputTokens", cacheReadInputTokens);
4384
+ if (cacheCreationInputTokens > 0)
4385
+ assignNumber("cacheCreationInputTokens", cacheCreationInputTokens);
4386
+ if (webSearchRequests > 0)
4387
+ assignNumber("webSearchRequests", webSearchRequests);
4388
+ if (webFetchRequests > 0)
4389
+ assignNumber("webFetchRequests", webFetchRequests);
4390
+ if (serviceTier)
4391
+ assignString("serviceTier", serviceTier);
4392
+ if (speed)
4393
+ assignString("speed", speed);
4394
+ return changed;
4395
+ }
4396
+ ensureObserveMetaRecord(key) {
4397
+ const providerMeta = isRecord(this.session.providerMeta) ? this.session.providerMeta : {};
4398
+ this.session.providerMeta = providerMeta;
4399
+ const existing = providerMeta[key];
4400
+ if (isRecord(existing)) {
4401
+ return existing;
4402
+ }
4403
+ const next = {};
4404
+ providerMeta[key] = next;
4405
+ return next;
4406
+ }
4407
+ assignObserveString(target, key, value) {
4408
+ const next = maybeString(value);
4409
+ if (next) {
4410
+ target[key] = next;
4411
+ }
4412
+ }
4160
4413
  handleSystem(record, capturedAt) {
4161
4414
  if (record.subtype !== "init") {
4162
4415
  return;
@@ -4186,19 +4439,41 @@ class ClaudeCodeHistoryParser {
4186
4439
  });
4187
4440
  }
4188
4441
  }
4442
+ handleUser(record, capturedAt) {
4443
+ const message = record.message && typeof record.message === "object" ? record.message : null;
4444
+ const content = message?.content;
4445
+ if (Array.isArray(content) && content.length > 0) {
4446
+ const toolResults = content.filter((entry) => {
4447
+ return !!entry && typeof entry === "object" && !Array.isArray(entry) && entry.type === "tool_result";
4448
+ });
4449
+ if (toolResults.length === content.length) {
4450
+ for (const toolResult of toolResults) {
4451
+ this.handleToolResult({
4452
+ ...toolResult,
4453
+ tool_use_id: typeof toolResult.tool_use_id === "string" ? toolResult.tool_use_id : toolResult.id,
4454
+ is_error: toolResult.is_error === true
4455
+ }, capturedAt);
4456
+ }
4457
+ return;
4458
+ }
4459
+ }
4460
+ this.startTurn(capturedAt);
4461
+ }
4189
4462
  handleAssistant(record, capturedAt) {
4190
4463
  const turn = this.ensureTurn(capturedAt);
4191
- if (this.sawStreamTextThisTurn) {
4192
- return;
4193
- }
4194
4464
  const content = record.message && typeof record.message === "object" ? record.message.content : record.content;
4195
4465
  if (!Array.isArray(content)) {
4466
+ this.maybeEndTurnFromAssistant(record, capturedAt);
4196
4467
  return;
4197
4468
  }
4469
+ const skipTextBlocks = this.sawStreamTextThisTurn;
4198
4470
  for (const part of content) {
4199
4471
  const contentPart = part;
4200
4472
  const contentType = typeof contentPart.type === "string" ? contentPart.type : "";
4201
4473
  if (contentType === "thinking" || contentType === "reasoning") {
4474
+ if (skipTextBlocks) {
4475
+ continue;
4476
+ }
4202
4477
  const block = this.startBlock(turn, capturedAt, {
4203
4478
  type: "reasoning",
4204
4479
  text: typeof contentPart.thinking === "string" ? contentPart.thinking : typeof contentPart.text === "string" ? contentPart.text : "",
@@ -4206,14 +4481,20 @@ class ClaudeCodeHistoryParser {
4206
4481
  });
4207
4482
  this.emitBlockEnd(capturedAt, turn, block, "completed");
4208
4483
  } else if (contentType === "text") {
4484
+ if (skipTextBlocks) {
4485
+ continue;
4486
+ }
4209
4487
  const block = this.startBlock(turn, capturedAt, {
4210
4488
  type: "text",
4211
4489
  text: typeof contentPart.text === "string" ? contentPart.text : "",
4212
4490
  status: "completed"
4213
4491
  });
4214
4492
  this.emitBlockEnd(capturedAt, turn, block, "completed");
4493
+ } else if (contentType === "tool_use") {
4494
+ this.handleToolUse(contentPart, capturedAt);
4215
4495
  }
4216
4496
  }
4497
+ this.maybeEndTurnFromAssistant(record, capturedAt);
4217
4498
  }
4218
4499
  handleStreamEvent(record, capturedAt) {
4219
4500
  const turn = this.ensureTurn(capturedAt);
@@ -4435,6 +4716,12 @@ class ClaudeCodeHistoryParser {
4435
4716
  this.emitError(turn, capturedAt, message);
4436
4717
  this.endTurn("failed", capturedAt);
4437
4718
  }
4719
+ maybeEndTurnFromAssistant(record, capturedAt) {
4720
+ const stopReason = record.message && typeof record.message === "object" ? record.message.stop_reason : record.stop_reason;
4721
+ if (stopReason === "end_turn") {
4722
+ this.endTurn("completed", capturedAt);
4723
+ }
4724
+ }
4438
4725
  startTurn(capturedAt) {
4439
4726
  if (this.currentTurn) {
4440
4727
  this.endTurn("stopped", capturedAt);
@@ -8539,11 +8826,11 @@ function formatTimestamp(value) {
8539
8826
  // ../../apps/desktop/src/core/pairing/runtime/bridge/server.ts
8540
8827
  import { readdirSync as readdirSync3, readFileSync as readFileSync9, realpathSync, statSync as statSync3 } from "fs";
8541
8828
  import { execSync as execSync3 } from "child_process";
8542
- import { basename as basename6, isAbsolute as isAbsolute3, join as join17, relative as relative2 } from "path";
8543
- import { homedir as homedir15 } from "os";
8829
+ import { basename as basename7, isAbsolute as isAbsolute3, join as join18, relative as relative2 } from "path";
8830
+ import { homedir as homedir16 } from "os";
8544
8831
 
8545
8832
  // ../../apps/desktop/src/core/mobile/service.ts
8546
- import { basename as basename5, resolve as resolve6 } from "path";
8833
+ import { basename as basename6, resolve as resolve7 } from "path";
8547
8834
 
8548
8835
  // ../runtime/src/harness-catalog.ts
8549
8836
  import { execFileSync } from "child_process";
@@ -10154,149 +10441,6 @@ function diagnoseAgentIdentity(identity, candidates) {
10154
10441
  var parseAgentSelector = parseAgentIdentity;
10155
10442
  var formatAgentSelector = formatAgentIdentity;
10156
10443
  var resolveAgentSelector = resolveAgentIdentity;
10157
- // ../protocol/dist/scout-agent-card.js
10158
- function buildScoutReturnAddress(input) {
10159
- const next = {
10160
- actorId: input.actorId,
10161
- handle: input.handle.trim()
10162
- };
10163
- if (input.displayName?.trim()) {
10164
- next.displayName = input.displayName.trim();
10165
- }
10166
- if (input.selector?.trim()) {
10167
- next.selector = input.selector.trim();
10168
- }
10169
- if (input.defaultSelector?.trim()) {
10170
- next.defaultSelector = input.defaultSelector.trim();
10171
- }
10172
- if (input.conversationId?.trim()) {
10173
- next.conversationId = input.conversationId.trim();
10174
- }
10175
- if (input.replyToMessageId?.trim()) {
10176
- next.replyToMessageId = input.replyToMessageId.trim();
10177
- }
10178
- if (input.nodeId?.trim()) {
10179
- next.nodeId = input.nodeId.trim();
10180
- }
10181
- if (input.projectRoot?.trim()) {
10182
- next.projectRoot = input.projectRoot.trim();
10183
- }
10184
- if (input.sessionId?.trim()) {
10185
- next.sessionId = input.sessionId.trim();
10186
- }
10187
- if (input.metadata && Object.keys(input.metadata).length > 0) {
10188
- next.metadata = input.metadata;
10189
- }
10190
- return next;
10191
- }
10192
- // ../protocol/dist/collaboration.js
10193
- function isQuestionTerminalState(state) {
10194
- return state === "closed" || state === "declined";
10195
- }
10196
- function isWorkItemTerminalState(state) {
10197
- return state === "done" || state === "cancelled";
10198
- }
10199
- function collaborationRequiresNextMoveOwner(record) {
10200
- if (record.kind === "question") {
10201
- return !isQuestionTerminalState(record.state);
10202
- }
10203
- return !isWorkItemTerminalState(record.state);
10204
- }
10205
- function collaborationRequiresOwner(record) {
10206
- return record.kind === "work_item" && !isWorkItemTerminalState(record.state);
10207
- }
10208
- function collaborationRequiresWaitingOn(record) {
10209
- return record.kind === "work_item" && record.state === "waiting";
10210
- }
10211
- function collaborationRequiresAcceptance(record) {
10212
- if (record.acceptanceState === "none") {
10213
- return false;
10214
- }
10215
- if (record.kind === "question") {
10216
- return Boolean(record.askedById && record.askedOfId);
10217
- }
10218
- return Boolean(record.requestedById);
10219
- }
10220
- function validateCollaborationRecord(record) {
10221
- const errors = [];
10222
- if (!record.id.trim()) {
10223
- errors.push("collaboration record id is required");
10224
- }
10225
- if (!record.title.trim()) {
10226
- errors.push("collaboration title is required");
10227
- }
10228
- if (!record.createdById.trim()) {
10229
- errors.push("createdById is required");
10230
- }
10231
- if (record.parentId && record.parentId === record.id) {
10232
- errors.push("parentId cannot reference the record itself");
10233
- }
10234
- if (record.createdAt > record.updatedAt) {
10235
- errors.push("updatedAt must be greater than or equal to createdAt");
10236
- }
10237
- if (collaborationRequiresOwner(record) && !record.ownerId) {
10238
- errors.push("non-terminal work items require ownerId");
10239
- }
10240
- if (collaborationRequiresNextMoveOwner(record) && !record.nextMoveOwnerId) {
10241
- errors.push("non-terminal collaboration records require nextMoveOwnerId");
10242
- }
10243
- if (record.kind === "work_item" && collaborationRequiresWaitingOn(record) && !record.waitingOn) {
10244
- errors.push("waiting work items require waitingOn");
10245
- }
10246
- if (record.kind === "question") {
10247
- if (record.spawnedWorkItemId && record.spawnedWorkItemId === record.id) {
10248
- errors.push("question spawnedWorkItemId cannot reference the question itself");
10249
- }
10250
- } else if (record.waitingOn?.targetId && record.waitingOn.targetId === record.id) {
10251
- errors.push("waitingOn.targetId cannot reference the work item itself");
10252
- }
10253
- if (record.acceptanceState !== "none" && !collaborationRequiresAcceptance(record)) {
10254
- errors.push("acceptanceState requires the corresponding requester and reviewer identities");
10255
- }
10256
- return errors;
10257
- }
10258
- function assertValidCollaborationRecord(record) {
10259
- const errors = validateCollaborationRecord(record);
10260
- if (errors.length > 0) {
10261
- throw new Error(errors.join("; "));
10262
- }
10263
- }
10264
- function validateCollaborationEvent(event, record) {
10265
- const errors = [];
10266
- if (!event.id.trim()) {
10267
- errors.push("collaboration event id is required");
10268
- }
10269
- if (!event.recordId.trim()) {
10270
- errors.push("collaboration event recordId is required");
10271
- }
10272
- if (!event.actorId.trim()) {
10273
- errors.push("collaboration event actorId is required");
10274
- }
10275
- if (record) {
10276
- if (record.id !== event.recordId) {
10277
- errors.push("collaboration event recordId does not match the target record");
10278
- }
10279
- if (record.kind !== event.recordKind) {
10280
- errors.push("collaboration event recordKind does not match the target record");
10281
- }
10282
- }
10283
- if (event.kind === "answered" && event.recordKind !== "question") {
10284
- errors.push("answered events only apply to questions");
10285
- }
10286
- if (event.kind === "declined" && event.recordKind !== "question") {
10287
- errors.push("declined events only apply to questions");
10288
- }
10289
- if ((event.kind === "waiting" || event.kind === "progressed" || event.kind === "review_requested" || event.kind === "done" || event.kind === "cancelled") && event.recordKind !== "work_item") {
10290
- errors.push(`${event.kind} events only apply to work items`);
10291
- }
10292
- return errors;
10293
- }
10294
- function assertValidCollaborationEvent(event, record) {
10295
- const errors = validateCollaborationEvent(event, record);
10296
- if (errors.length > 0) {
10297
- throw new Error(errors.join("; "));
10298
- }
10299
- }
10300
10444
  // ../runtime/src/user-project-hints.ts
10301
10445
  import { readdir, readFile as readFile3, stat } from "fs/promises";
10302
10446
  import { homedir as homedir11 } from "os";
@@ -12347,9 +12491,9 @@ async function ensureRelayAgentConfigured(value, options = {}) {
12347
12491
 
12348
12492
  // ../runtime/src/local-agents.ts
12349
12493
  import { execFileSync as execFileSync3, execSync as execSync2 } from "child_process";
12350
- import { existsSync as existsSync13, readFileSync as readFileSync8 } from "fs";
12494
+ import { existsSync as existsSync14, readFileSync as readFileSync8 } from "fs";
12351
12495
  import { mkdir as mkdir6, rm as rm5, stat as stat3, writeFile as writeFile6 } from "fs/promises";
12352
- import { basename as basename4, dirname as dirname6, join as join15, resolve as resolve5 } from "path";
12496
+ import { basename as basename5, dirname as dirname7, join as join16, resolve as resolve6 } from "path";
12353
12497
  import { fileURLToPath as fileURLToPath5 } from "url";
12354
12498
 
12355
12499
  // ../runtime/src/claude-stream-json.ts
@@ -13693,10 +13837,116 @@ function buildCollaborationContractPrompt(agentId) {
13693
13837
 
13694
13838
  // ../runtime/src/broker-service.ts
13695
13839
  import { spawnSync } from "child_process";
13696
- import { existsSync as existsSync12, mkdirSync as mkdirSync8, readFileSync as readFileSync7, rmSync as rmSync2, writeFileSync as writeFileSync5 } from "fs";
13840
+ import { existsSync as existsSync13, mkdirSync as mkdirSync8, readFileSync as readFileSync7, rmSync as rmSync2, writeFileSync as writeFileSync5 } from "fs";
13841
+ import { homedir as homedir14 } from "os";
13842
+ import { dirname as dirname6, join as join15, resolve as resolve5 } from "path";
13843
+ import { fileURLToPath as fileURLToPath4 } from "url";
13844
+
13845
+ // ../runtime/src/tool-resolution.ts
13846
+ import { accessSync as accessSync2, constants as constants4, existsSync as existsSync12 } from "fs";
13697
13847
  import { homedir as homedir13 } from "os";
13698
13848
  import { basename as basename3, dirname as dirname5, join as join14, resolve as resolve4 } from "path";
13699
- import { fileURLToPath as fileURLToPath4 } from "url";
13849
+ var DEFAULT_COMMON_EXECUTABLE_DIRECTORIES = [
13850
+ join14(homedir13(), ".bun", "bin"),
13851
+ "/opt/homebrew/bin",
13852
+ "/usr/local/bin"
13853
+ ];
13854
+ function expandHomePath3(value, env = process.env) {
13855
+ const home = env.HOME ?? homedir13();
13856
+ if (value === "~") {
13857
+ return home;
13858
+ }
13859
+ if (value.startsWith("~/")) {
13860
+ return join14(home, value.slice(2));
13861
+ }
13862
+ return value;
13863
+ }
13864
+ function isExecutablePath(candidate) {
13865
+ if (!candidate) {
13866
+ return false;
13867
+ }
13868
+ try {
13869
+ accessSync2(candidate, constants4.X_OK);
13870
+ return true;
13871
+ } catch {
13872
+ return false;
13873
+ }
13874
+ }
13875
+ function splitPathEntries(env = process.env) {
13876
+ const separator = process.platform === "win32" ? ";" : ":";
13877
+ return (env.PATH ?? "").split(separator).filter(Boolean);
13878
+ }
13879
+ function dedupeDirectories(values, env) {
13880
+ const seen = new Set;
13881
+ const resolvedEntries = [];
13882
+ for (const value of values) {
13883
+ const normalized = resolve4(expandHomePath3(value, env));
13884
+ if (seen.has(normalized)) {
13885
+ continue;
13886
+ }
13887
+ seen.add(normalized);
13888
+ resolvedEntries.push(normalized);
13889
+ }
13890
+ return resolvedEntries;
13891
+ }
13892
+ function resolveExecutableFromSearch(options) {
13893
+ const env = options.env ?? process.env;
13894
+ const envKeys = options.envKeys ?? [];
13895
+ for (const envKey of envKeys) {
13896
+ const explicit = env[envKey]?.trim();
13897
+ if (!explicit) {
13898
+ continue;
13899
+ }
13900
+ const expanded = expandHomePath3(explicit, env);
13901
+ if (isExecutablePath(expanded)) {
13902
+ return { path: resolve4(expanded), source: "env" };
13903
+ }
13904
+ const foundOnPath = findExecutableOnSearchPath(explicit, env);
13905
+ if (foundOnPath) {
13906
+ return { path: foundOnPath.path, source: "env" };
13907
+ }
13908
+ }
13909
+ const commonDirectories = dedupeDirectories([...options.commonDirectories ?? DEFAULT_COMMON_EXECUTABLE_DIRECTORIES], env);
13910
+ const searchDirectories = dedupeDirectories([
13911
+ ...splitPathEntries(env),
13912
+ ...options.extraDirectories ?? [],
13913
+ ...commonDirectories
13914
+ ], env);
13915
+ for (const directory of searchDirectories) {
13916
+ for (const name of options.names) {
13917
+ const candidate = join14(directory, name);
13918
+ if (isExecutablePath(candidate)) {
13919
+ return {
13920
+ path: candidate,
13921
+ source: commonDirectories.includes(directory) ? "common-path" : "path"
13922
+ };
13923
+ }
13924
+ }
13925
+ }
13926
+ return null;
13927
+ }
13928
+ function resolveBunExecutable2(env = process.env) {
13929
+ return resolveExecutableFromSearch({
13930
+ env,
13931
+ envKeys: ["OPENSCOUT_BUN_BIN", "SCOUT_BUN_BIN", "BUN_BIN"],
13932
+ names: ["bun"]
13933
+ });
13934
+ }
13935
+ function findExecutableOnSearchPath(name, env) {
13936
+ const searchDirectories = dedupeDirectories([
13937
+ ...splitPathEntries(env),
13938
+ ...DEFAULT_COMMON_EXECUTABLE_DIRECTORIES
13939
+ ], env);
13940
+ for (const directory of searchDirectories) {
13941
+ const candidate = join14(directory, name);
13942
+ if (isExecutablePath(candidate)) {
13943
+ return { path: candidate, source: "path" };
13944
+ }
13945
+ }
13946
+ return null;
13947
+ }
13948
+
13949
+ // ../runtime/src/broker-service.ts
13700
13950
  function isTmpPath(p) {
13701
13951
  return /^\/(?:private\/)?tmp\//.test(p);
13702
13952
  }
@@ -13735,17 +13985,17 @@ function runtimePackageDir() {
13735
13985
  const fromCwd = findWorkspaceRuntimeDir(process.cwd());
13736
13986
  if (fromCwd)
13737
13987
  return fromCwd;
13738
- const moduleDir = dirname5(fileURLToPath4(import.meta.url));
13739
- return resolve4(moduleDir, "..");
13988
+ const moduleDir = dirname6(fileURLToPath4(import.meta.url));
13989
+ return resolve5(moduleDir, "..");
13740
13990
  }
13741
13991
  function isInstalledRuntimePackageDir(candidate) {
13742
- return existsSync12(join14(candidate, "package.json")) && existsSync12(join14(candidate, "bin", "openscout-runtime.mjs"));
13992
+ return existsSync13(join15(candidate, "package.json")) && existsSync13(join15(candidate, "bin", "openscout-runtime.mjs"));
13743
13993
  }
13744
13994
  function findGlobalRuntimeDir() {
13745
13995
  const candidates = [
13746
- join14(homedir13(), ".bun", "node_modules", "@openscout", "runtime"),
13747
- join14(homedir13(), ".bun", "install", "global", "node_modules", "@openscout", "runtime"),
13748
- join14(homedir13(), ".bun", "install", "global", "node_modules", "@openscout", "scout", "node_modules", "@openscout", "runtime")
13996
+ join15(homedir14(), ".bun", "node_modules", "@openscout", "runtime"),
13997
+ join15(homedir14(), ".bun", "install", "global", "node_modules", "@openscout", "runtime"),
13998
+ join15(homedir14(), ".bun", "install", "global", "node_modules", "@openscout", "scout", "node_modules", "@openscout", "runtime")
13749
13999
  ];
13750
14000
  for (const c of candidates) {
13751
14001
  if (isInstalledRuntimePackageDir(c))
@@ -13755,11 +14005,11 @@ function findGlobalRuntimeDir() {
13755
14005
  const result = spawnSync("which", ["scout"], { encoding: "utf8", timeout: 3000 });
13756
14006
  const scoutBin = result.stdout?.trim();
13757
14007
  if (scoutBin) {
13758
- const scoutPkg = resolve4(scoutBin, "..", "..");
13759
- const nested = join14(scoutPkg, "node_modules", "@openscout", "runtime");
14008
+ const scoutPkg = resolve5(scoutBin, "..", "..");
14009
+ const nested = join15(scoutPkg, "node_modules", "@openscout", "runtime");
13760
14010
  if (isInstalledRuntimePackageDir(nested))
13761
14011
  return nested;
13762
- const sibling = resolve4(scoutPkg, "..", "runtime");
14012
+ const sibling = resolve5(scoutPkg, "..", "runtime");
13763
14013
  if (isInstalledRuntimePackageDir(sibling))
13764
14014
  return sibling;
13765
14015
  }
@@ -13767,38 +14017,24 @@ function findGlobalRuntimeDir() {
13767
14017
  return null;
13768
14018
  }
13769
14019
  function findWorkspaceRuntimeDir(startDir) {
13770
- let current = resolve4(startDir);
14020
+ let current = resolve5(startDir);
13771
14021
  while (true) {
13772
- const candidate = join14(current, "packages", "runtime");
13773
- if (existsSync12(join14(candidate, "package.json")) && existsSync12(join14(candidate, "src"))) {
14022
+ const candidate = join15(current, "packages", "runtime");
14023
+ if (existsSync13(join15(candidate, "package.json")) && existsSync13(join15(candidate, "src"))) {
13774
14024
  return candidate;
13775
14025
  }
13776
- const parent = dirname5(current);
14026
+ const parent = dirname6(current);
13777
14027
  if (parent === current)
13778
14028
  return null;
13779
14029
  current = parent;
13780
14030
  }
13781
14031
  }
13782
- function resolveBunExecutable2() {
13783
- const explicit = process.env.OPENSCOUT_BUN_BIN ?? process.env.BUN_BIN;
13784
- if (explicit && explicit.trim().length > 0) {
13785
- return explicit;
13786
- }
13787
- if (basename3(process.execPath).startsWith("bun") && existsSync12(process.execPath)) {
13788
- return process.execPath;
13789
- }
13790
- const pathEntries = (process.env.PATH ?? "").split(":").filter(Boolean);
13791
- for (const entry of pathEntries) {
13792
- const candidate = join14(entry, "bun");
13793
- if (existsSync12(candidate)) {
13794
- return candidate;
13795
- }
13796
- }
13797
- const homeBun = join14(homedir13(), ".bun", "bin", "bun");
13798
- if (existsSync12(homeBun)) {
13799
- return homeBun;
14032
+ function resolveBunExecutable3() {
14033
+ const bun = resolveBunExecutable2(process.env);
14034
+ if (bun) {
14035
+ return bun.path;
13800
14036
  }
13801
- return "bun";
14037
+ throw new Error("Unable to locate Bun for broker service management. Install Bun or set OPENSCOUT_BUN_BIN.");
13802
14038
  }
13803
14039
  function resolveBrokerServiceMode() {
13804
14040
  const explicit = (process.env.OPENSCOUT_BROKER_SERVICE_MODE ?? "").trim().toLowerCase();
@@ -13837,15 +14073,15 @@ function resolveBrokerServiceConfig() {
13837
14073
  const label = resolveBrokerServiceLabel(mode);
13838
14074
  const uid = typeof process.getuid === "function" ? process.getuid() : Number.parseInt(process.env.UID ?? "0", 10);
13839
14075
  const supportPaths = resolveOpenScoutSupportPaths();
13840
- const defaultSupportDir = join14(homedir13(), "Library", "Application Support", "OpenScout");
14076
+ const defaultSupportDir = join15(homedir14(), "Library", "Application Support", "OpenScout");
13841
14077
  const supportDirectory = isTmpPath(supportPaths.supportDirectory) ? defaultSupportDir : supportPaths.supportDirectory;
13842
- const logsDirectory = join14(supportDirectory, "logs", "broker");
13843
- const controlHome = isTmpPath(supportPaths.controlHome) ? join14(homedir13(), ".openscout", "control-plane") : supportPaths.controlHome;
14078
+ const logsDirectory = join15(supportDirectory, "logs", "broker");
14079
+ const controlHome = isTmpPath(supportPaths.controlHome) ? join15(homedir14(), ".openscout", "control-plane") : supportPaths.controlHome;
13844
14080
  const advertiseScope = resolveAdvertiseScope();
13845
14081
  const brokerHost = resolveBrokerHost(advertiseScope);
13846
14082
  const brokerPort = Number.parseInt(process.env.OPENSCOUT_BROKER_PORT ?? String(DEFAULT_BROKER_PORT), 10);
13847
14083
  const brokerUrl = process.env.OPENSCOUT_BROKER_URL ?? buildDefaultBrokerUrl(brokerHost, brokerPort);
13848
- const launchAgentPath = join14(homedir13(), "Library", "LaunchAgents", `${label}.plist`);
14084
+ const launchAgentPath = join15(homedir14(), "Library", "LaunchAgents", `${label}.plist`);
13849
14085
  return {
13850
14086
  label,
13851
14087
  mode,
@@ -13855,11 +14091,11 @@ function resolveBrokerServiceConfig() {
13855
14091
  launchAgentPath,
13856
14092
  supportDirectory,
13857
14093
  logsDirectory,
13858
- stdoutLogPath: join14(logsDirectory, "stdout.log"),
13859
- stderrLogPath: join14(logsDirectory, "stderr.log"),
14094
+ stdoutLogPath: join15(logsDirectory, "stdout.log"),
14095
+ stderrLogPath: join15(logsDirectory, "stderr.log"),
13860
14096
  controlHome,
13861
14097
  runtimePackageDir: runtimePackageDir(),
13862
- bunExecutable: resolveBunExecutable2(),
14098
+ bunExecutable: resolveBunExecutable3(),
13863
14099
  brokerHost,
13864
14100
  brokerPort,
13865
14101
  brokerUrl,
@@ -13876,7 +14112,7 @@ function renderLaunchAgentPlist(config) {
13876
14112
  OPENSCOUT_BROKER_SERVICE_MODE: config.mode,
13877
14113
  OPENSCOUT_BROKER_SERVICE_LABEL: config.label,
13878
14114
  OPENSCOUT_ADVERTISE_SCOPE: config.advertiseScope,
13879
- HOME: homedir13(),
14115
+ HOME: homedir14(),
13880
14116
  PATH: launchPath,
13881
14117
  ...collectOptionalEnvVars([
13882
14118
  "OPENSCOUT_MESH_ID",
@@ -13902,7 +14138,7 @@ function renderLaunchAgentPlist(config) {
13902
14138
  <key>ProgramArguments</key>
13903
14139
  <array>
13904
14140
  <string>${xmlEscape(config.bunExecutable)}</string>
13905
- <string>${xmlEscape(join14(config.runtimePackageDir, "bin", "openscout-runtime.mjs"))}</string>
14141
+ <string>${xmlEscape(join15(config.runtimePackageDir, "bin", "openscout-runtime.mjs"))}</string>
13906
14142
  <string>broker</string>
13907
14143
  </array>
13908
14144
  <key>WorkingDirectory</key>
@@ -13937,7 +14173,7 @@ function collectOptionalEnvVars(keys) {
13937
14173
  }
13938
14174
  function resolveLaunchAgentPATH() {
13939
14175
  const entries = [
13940
- join14(homedir13(), ".bun", "bin"),
14176
+ join15(homedir14(), ".bun", "bin"),
13941
14177
  ...(process.env.PATH ?? "").split(":").filter(Boolean),
13942
14178
  "/opt/homebrew/bin",
13943
14179
  "/usr/local/bin",
@@ -13952,7 +14188,7 @@ function xmlEscape(value) {
13952
14188
  return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&apos;");
13953
14189
  }
13954
14190
  function ensureParentDirectory(filePath) {
13955
- mkdirSync8(dirname5(filePath), { recursive: true });
14191
+ mkdirSync8(dirname6(filePath), { recursive: true });
13956
14192
  }
13957
14193
  function ensureServiceDirectories(config) {
13958
14194
  ensureOpenScoutCleanSlateSync();
@@ -13985,7 +14221,7 @@ function launchctlPath() {
13985
14221
  return "/bin/launchctl";
13986
14222
  }
13987
14223
  function readLogLines(path2) {
13988
- if (!existsSync12(path2)) {
14224
+ if (!existsSync13(path2)) {
13989
14225
  return [];
13990
14226
  }
13991
14227
  return readFileSync7(path2, "utf8").split(`
@@ -14085,7 +14321,7 @@ async function brokerServiceStatus(config = resolveBrokerServiceConfig()) {
14085
14321
  ensureServiceDirectories(config);
14086
14322
  const launchctl = inspectLaunchctl(config);
14087
14323
  const health = await fetchHealthSnapshot(config);
14088
- const installed = existsSync12(config.launchAgentPath);
14324
+ const installed = existsSync13(config.launchAgentPath);
14089
14325
  const lastLogLine = health.reachable ? readLastLogLine([config.stdoutLogPath, config.stderrLogPath]) : readLastLogLine([config.stderrLogPath, config.stdoutLogPath]);
14090
14326
  return {
14091
14327
  label: config.label,
@@ -14128,7 +14364,7 @@ async function startBrokerService(config = resolveBrokerServiceConfig()) {
14128
14364
  throw new Error(status.lastLogLine ?? status.health.error ?? "Broker service did not become healthy.");
14129
14365
  }
14130
14366
  function sleep(ms) {
14131
- return new Promise((resolve5) => setTimeout(resolve5, ms));
14367
+ return new Promise((resolve6) => setTimeout(resolve6, ms));
14132
14368
  }
14133
14369
  async function stopBrokerService(config = resolveBrokerServiceConfig()) {
14134
14370
  runCommand(launchctlPath(), ["bootout", config.serviceTarget], { allowFailure: true });
@@ -14147,7 +14383,7 @@ async function restartBrokerService(config = resolveBrokerServiceConfig()) {
14147
14383
  }
14148
14384
  async function uninstallBrokerService(config = resolveBrokerServiceConfig()) {
14149
14385
  await stopBrokerService(config);
14150
- if (existsSync12(config.launchAgentPath)) {
14386
+ if (existsSync13(config.launchAgentPath)) {
14151
14387
  rmSync2(config.launchAgentPath, { force: true });
14152
14388
  }
14153
14389
  return brokerServiceStatus(config);
@@ -14217,8 +14453,8 @@ var LOCAL_AGENT_SYSTEM_PROMPT_TEMPLATE_HINT = [
14217
14453
  ].join("");
14218
14454
 
14219
14455
  // ../runtime/src/local-agents.ts
14220
- var MODULE_DIRECTORY = dirname6(fileURLToPath5(import.meta.url));
14221
- var OPENSCOUT_REPO_ROOT = resolve5(MODULE_DIRECTORY, "..", "..", "..");
14456
+ var MODULE_DIRECTORY = dirname7(fileURLToPath5(import.meta.url));
14457
+ var OPENSCOUT_REPO_ROOT = resolve6(MODULE_DIRECTORY, "..", "..", "..");
14222
14458
  var DEFAULT_LOCAL_AGENT_CAPABILITIES = ["chat", "invoke", "deliver"];
14223
14459
  var DEFAULT_LOCAL_AGENT_HARNESS = "claude";
14224
14460
  function resolveRelayHub() {
@@ -14226,18 +14462,18 @@ function resolveRelayHub() {
14226
14462
  }
14227
14463
  function resolveProjectsRoot(projectPath) {
14228
14464
  if (process.env.OPENSCOUT_PROJECTS_ROOT?.trim()) {
14229
- return resolve5(process.env.OPENSCOUT_PROJECTS_ROOT.trim());
14465
+ return resolve6(process.env.OPENSCOUT_PROJECTS_ROOT.trim());
14230
14466
  }
14231
14467
  try {
14232
14468
  const supportPaths = resolveOpenScoutSupportPaths();
14233
- if (!existsSync13(supportPaths.settingsPath)) {
14234
- return dirname6(projectPath);
14469
+ if (!existsSync14(supportPaths.settingsPath)) {
14470
+ return dirname7(projectPath);
14235
14471
  }
14236
14472
  const raw = JSON.parse(readFileSync8(supportPaths.settingsPath, "utf8"));
14237
14473
  const workspaceRoot = raw.discovery?.workspaceRoots?.find((entry) => typeof entry === "string" && entry.trim().length > 0);
14238
- return workspaceRoot ? resolve5(workspaceRoot) : dirname6(projectPath);
14474
+ return workspaceRoot ? resolve6(workspaceRoot) : dirname7(projectPath);
14239
14475
  } catch {
14240
- return dirname6(projectPath);
14476
+ return dirname7(projectPath);
14241
14477
  }
14242
14478
  }
14243
14479
  function resolveBrokerUrl() {
@@ -14247,7 +14483,7 @@ function nowSeconds2() {
14247
14483
  return Math.floor(Date.now() / 1000);
14248
14484
  }
14249
14485
  function scoutCliPath() {
14250
- return join15(OPENSCOUT_REPO_ROOT, "packages", "cli", "bin", "scout.mjs");
14486
+ return join16(OPENSCOUT_REPO_ROOT, "packages", "cli", "bin", "scout.mjs");
14251
14487
  }
14252
14488
  function legacyNodeBrokerRelayCommand() {
14253
14489
  return `node ${JSON.stringify(scoutCliPath())}`;
@@ -14260,13 +14496,13 @@ function titleCaseLocalAgentName(value) {
14260
14496
  }
14261
14497
  function resolveScoutSkillPath() {
14262
14498
  const candidatePaths = [
14263
- join15(OPENSCOUT_REPO_ROOT, ".agents", "skills", "scout", "SKILL.md"),
14264
- join15(process.env.HOME ?? "", ".agents", "skills", "scout", "SKILL.md"),
14265
- join15(OPENSCOUT_REPO_ROOT, ".agents", "skills", "relay-agent-comms", "SKILL.md"),
14266
- join15(process.env.HOME ?? "", ".agents", "skills", "relay-agent-comms", "SKILL.md")
14499
+ join16(OPENSCOUT_REPO_ROOT, ".agents", "skills", "scout", "SKILL.md"),
14500
+ join16(process.env.HOME ?? "", ".agents", "skills", "scout", "SKILL.md"),
14501
+ join16(OPENSCOUT_REPO_ROOT, ".agents", "skills", "relay-agent-comms", "SKILL.md"),
14502
+ join16(process.env.HOME ?? "", ".agents", "skills", "relay-agent-comms", "SKILL.md")
14267
14503
  ];
14268
14504
  for (const path2 of candidatePaths) {
14269
- if (existsSync13(path2)) {
14505
+ if (existsSync14(path2)) {
14270
14506
  return path2;
14271
14507
  }
14272
14508
  }
@@ -14317,7 +14553,7 @@ function buildLocalAgentCollaborationPrompt(context) {
14317
14553
  function buildLocalAgentTmuxProtocolPrompt(context) {
14318
14554
  return [
14319
14555
  "Relay protocol:",
14320
- ` - Read recent context with: ${context.relayCommand} read --as ${context.agentId}`,
14556
+ ` - Read recent context when needed with: ${context.relayCommand} latest --agent ${context.agentId} --limit 20`,
14321
14557
  ` - Tell one agent with: ${context.relayCommand} send --as ${context.agentId} "@<agent> your message"`,
14322
14558
  ` - Ask one agent and stay attached with: ${context.relayCommand} ask --to <agent> --as ${context.agentId} "your request"`,
14323
14559
  "",
@@ -14329,9 +14565,10 @@ function buildLocalAgentTmuxProtocolPrompt(context) {
14329
14565
  " - If you need multiple agents, use separate DMs or an explicit channel; do not guess a venue from multiple mentions",
14330
14566
  " - Do not use channel.shared for ordinary delegation or follow-up; reserve it for explicit group updates or broadcasts",
14331
14567
  " - If a short @handle may be ambiguous, resolve the exact target before sending; do not guess and do not fall back to shared",
14568
+ " - Treat known offline / on-demand agents as wakeable: use send or ask first and let the broker wake them; only surface ambiguity or unknown-target failures to the operator",
14332
14569
  " - Use send for tells and status; use ask when the meaning is 'do this and get back to me'",
14333
14570
  " - When replying to an [ask:<id>] request, include the same [ask:<id>] tag in your reply",
14334
- " - Use the broker-backed relay read command above to inspect recent context before responding",
14571
+ " - Use the broker-backed latest command above only when recent context is needed before responding",
14335
14572
  ` - Follow the scout skill at ${context.scoutSkill} for agent-to-agent communication`
14336
14573
  ].join(`
14337
14574
  `);
@@ -14342,7 +14579,7 @@ function buildLocalAgentDirectProtocolPrompt(context) {
14342
14579
  " - You are invoked directly by the OpenScout broker",
14343
14580
  " - Return your final answer in the assistant message for the current turn",
14344
14581
  " - Do not shell out to send the final answer through relay yourself",
14345
- ` - If you need recent relay context, inspect it with: ${context.relayCommand} read --as ${context.agentId}`,
14582
+ ` - If you need recent broker context, inspect it with: ${context.relayCommand} latest --agent ${context.agentId} --limit 20`,
14346
14583
  ` - If you need to tell one agent something, use: ${context.relayCommand} send --as ${context.agentId} "@<agent> your message"`,
14347
14584
  ` - If you need another agent to do work, use: ${context.relayCommand} ask --to <agent> --as ${context.agentId} "your request"`,
14348
14585
  " - Default Scout loop: resolve identity, resolve one target, choose DM vs explicit channel, keep follow-up in that same venue",
@@ -14350,6 +14587,7 @@ function buildLocalAgentDirectProtocolPrompt(context) {
14350
14587
  " - If you need multiple agents, use separate DMs or an explicit channel; do not guess a venue from multiple mentions",
14351
14588
  " - Do not use channel.shared for ordinary delegation or follow-up; reserve it for explicit group updates or broadcasts",
14352
14589
  " - If a short @handle may be ambiguous, resolve the exact target before sending; do not guess and do not fall back to shared",
14590
+ " - Treat known offline / on-demand agents as wakeable: use send or ask first and let the broker wake them; only surface ambiguity or unknown-target failures to the operator",
14353
14591
  " - Use send for tells and status; use ask when the meaning is 'do this and get back to me'",
14354
14592
  ` - Follow the scout skill at ${context.scoutSkill} for agent-to-agent communication`
14355
14593
  ].join(`
@@ -14412,7 +14650,7 @@ function buildLegacySimpleRelayPrompt(agentId, projectName, projectPath, relayCo
14412
14650
  "A primary agent may call into you for context, execution, follow-through, and handoff.",
14413
14651
  "",
14414
14652
  `You have full access to the codebase at ${projectPath}.`,
14415
- `There is a structured relay event stream at ${join15(relayHub, "channel.jsonl")} shared by all agents.`,
14653
+ `There is a structured relay event stream at ${join16(relayHub, "channel.jsonl")} shared by all agents.`,
14416
14654
  "",
14417
14655
  "Your job:",
14418
14656
  ` - Respond to @${agentId} mentions from other agents`,
@@ -14516,17 +14754,17 @@ async function writeLocalAgentRegistry(registry) {
14516
14754
  }
14517
14755
  await writeRelayAgentOverrides(nextOverrides);
14518
14756
  }
14519
- function expandHomePath3(value) {
14757
+ function expandHomePath4(value) {
14520
14758
  if (value === "~") {
14521
14759
  return process.env.HOME ?? process.cwd();
14522
14760
  }
14523
14761
  if (value.startsWith("~/")) {
14524
- return join15(process.env.HOME ?? process.cwd(), value.slice(2));
14762
+ return join16(process.env.HOME ?? process.cwd(), value.slice(2));
14525
14763
  }
14526
14764
  return value;
14527
14765
  }
14528
14766
  function normalizeProjectPath(value) {
14529
- return resolve5(expandHomePath3(value.trim() || "."));
14767
+ return resolve6(expandHomePath4(value.trim() || "."));
14530
14768
  }
14531
14769
  function normalizeTmuxSessionName2(value, agentId) {
14532
14770
  const fallback = `relay-${agentId}`;
@@ -14789,7 +15027,7 @@ function recordForHarness(record, harnessOverride) {
14789
15027
  function normalizeLocalAgentRecord(agentId, record) {
14790
15028
  const cwd = normalizeProjectPath(record.cwd || process.cwd());
14791
15029
  const projectRoot = normalizeProjectPath(record.projectRoot || cwd);
14792
- const project = record.project?.trim() || basename4(projectRoot);
15030
+ const project = record.project?.trim() || basename5(projectRoot);
14793
15031
  const definitionId = record.definitionId?.trim() || agentId;
14794
15032
  const defaultHarness = activeLocalHarness(record);
14795
15033
  const harnessProfiles = normalizeLocalHarnessProfiles(agentId, {
@@ -14854,7 +15092,7 @@ function localAgentRecordFromResolvedConfig(config) {
14854
15092
  function localAgentRecordFromRelayAgentOverride(agentId, override) {
14855
15093
  return normalizeLocalAgentRecord(agentId, {
14856
15094
  definitionId: override.definitionId ?? agentId,
14857
- project: override.projectName ?? basename4(override.projectRoot || override.runtime?.cwd || agentId),
15095
+ project: override.projectName ?? basename5(override.projectRoot || override.runtime?.cwd || agentId),
14858
15096
  projectRoot: override.projectRoot ?? override.runtime?.cwd,
14859
15097
  tmuxSession: override.runtime?.sessionId ?? `relay-${agentId}`,
14860
15098
  cwd: override.runtime?.cwd ?? override.projectRoot,
@@ -14950,7 +15188,7 @@ function buildLocalAgentBootstrapPrompt(_harness, _systemPrompt, initialMessage)
14950
15188
  function buildLocalAgentLaunchCommand(agentName, record, projectPath, promptFile, workerScript) {
14951
15189
  const extraArgs = shellQuoteArguments(normalizeLaunchArgsForHarness(normalizeLocalAgentHarness(record.harness), record.launchArgs));
14952
15190
  if (normalizeLocalAgentHarness(record.harness) === "codex") {
14953
- return `exec bash ${JSON.stringify(workerScript ?? join15(relayAgentRuntimeDirectory(agentName), "codex-worker.sh"))}`;
15191
+ return `exec bash ${JSON.stringify(workerScript ?? join16(relayAgentRuntimeDirectory(agentName), "codex-worker.sh"))}`;
14954
15192
  }
14955
15193
  return [
14956
15194
  "claude",
@@ -14996,7 +15234,7 @@ async function ensureLocalAgentOnline(agentName, record) {
14996
15234
  return normalizedRecord;
14997
15235
  }
14998
15236
  const projectPath = normalizedRecord.cwd;
14999
- const projectName = normalizedRecord.project || basename4(projectPath);
15237
+ const projectName = normalizedRecord.project || basename5(projectPath);
15000
15238
  const systemPromptTemplate = normalizedRecord.systemPrompt || buildLocalAgentSystemPromptTemplate();
15001
15239
  const systemPrompt = renderLocalAgentSystemPromptTemplate(systemPromptTemplate, buildLocalAgentTemplateContext(agentName, projectName, projectPath), { transport: normalizedRecord.transport });
15002
15240
  const agentRuntimeDir = relayAgentRuntimeDirectory(agentName);
@@ -15004,7 +15242,7 @@ async function ensureLocalAgentOnline(agentName, record) {
15004
15242
  await mkdir6(agentRuntimeDir, { recursive: true });
15005
15243
  await mkdir6(logsDir, { recursive: true });
15006
15244
  if (normalizedRecord.transport === "codex_app_server") {
15007
- await writeFile6(join15(agentRuntimeDir, "prompt.txt"), systemPrompt);
15245
+ await writeFile6(join16(agentRuntimeDir, "prompt.txt"), systemPrompt);
15008
15246
  await ensureCodexAppServerAgentOnline(buildCodexAgentSessionOptions(agentName, normalizedRecord, systemPrompt));
15009
15247
  const registry2 = await readLocalAgentRegistry();
15010
15248
  registry2[agentName] = {
@@ -15016,7 +15254,7 @@ async function ensureLocalAgentOnline(agentName, record) {
15016
15254
  return registry2[agentName];
15017
15255
  }
15018
15256
  if (normalizedRecord.transport === "claude_stream_json") {
15019
- await writeFile6(join15(agentRuntimeDir, "prompt.txt"), systemPrompt);
15257
+ await writeFile6(join16(agentRuntimeDir, "prompt.txt"), systemPrompt);
15020
15258
  await ensureClaudeStreamJsonAgentOnline(buildClaudeAgentSessionOptions(agentName, normalizedRecord, systemPrompt));
15021
15259
  const registry2 = await readLocalAgentRegistry();
15022
15260
  registry2[agentName] = {
@@ -15029,17 +15267,17 @@ async function ensureLocalAgentOnline(agentName, record) {
15029
15267
  }
15030
15268
  const initialMessage = buildLocalAgentInitialMessage(projectName, agentName);
15031
15269
  const bootstrapPrompt = buildLocalAgentBootstrapPrompt(normalizeLocalAgentHarness(normalizedRecord.harness), systemPrompt, initialMessage);
15032
- const queueDirectory = join15(agentRuntimeDir, "queue");
15033
- const processingDirectory = join15(queueDirectory, "processing");
15034
- const processedDirectory = join15(queueDirectory, "processed");
15035
- const promptFile = join15(agentRuntimeDir, "prompt.txt");
15036
- const initialFile = join15(agentRuntimeDir, "initial.txt");
15037
- const launchScript = join15(agentRuntimeDir, "launch.sh");
15038
- const workerScript = join15(agentRuntimeDir, "codex-worker.sh");
15039
- const codexSessionIdFile = join15(agentRuntimeDir, "codex-session-id.txt");
15040
- const stateFile = join15(agentRuntimeDir, "state.json");
15041
- const stdoutLogFile = join15(logsDir, "stdout.log");
15042
- const stderrLogFile = join15(logsDir, "stderr.log");
15270
+ const queueDirectory = join16(agentRuntimeDir, "queue");
15271
+ const processingDirectory = join16(queueDirectory, "processing");
15272
+ const processedDirectory = join16(queueDirectory, "processed");
15273
+ const promptFile = join16(agentRuntimeDir, "prompt.txt");
15274
+ const initialFile = join16(agentRuntimeDir, "initial.txt");
15275
+ const launchScript = join16(agentRuntimeDir, "launch.sh");
15276
+ const workerScript = join16(agentRuntimeDir, "codex-worker.sh");
15277
+ const codexSessionIdFile = join16(agentRuntimeDir, "codex-session-id.txt");
15278
+ const stateFile = join16(agentRuntimeDir, "state.json");
15279
+ const stdoutLogFile = join16(logsDir, "stdout.log");
15280
+ const stderrLogFile = join16(logsDir, "stderr.log");
15043
15281
  await writeFile6(promptFile, systemPrompt);
15044
15282
  await writeFile6(initialFile, bootstrapPrompt);
15045
15283
  await writeFile6(stderrLogFile, "");
@@ -15101,10 +15339,10 @@ async function ensureLocalAgentOnline(agentName, record) {
15101
15339
  if (isLocalAgentSessionAlive(normalizedRecord.tmuxSession)) {
15102
15340
  break;
15103
15341
  }
15104
- await new Promise((resolve6) => setTimeout(resolve6, 100));
15342
+ await new Promise((resolve7) => setTimeout(resolve7, 100));
15105
15343
  }
15106
15344
  if (!isLocalAgentSessionAlive(normalizedRecord.tmuxSession)) {
15107
- const stderrTail = existsSync13(stderrLogFile) ? readFileSync8(stderrLogFile, "utf8").trim().split(/\r?\n/).slice(-10).join(`
15345
+ const stderrTail = existsSync14(stderrLogFile) ? readFileSync8(stderrLogFile, "utf8").trim().split(/\r?\n/).slice(-10).join(`
15108
15346
  `).trim() : "";
15109
15347
  throw new Error(stderrTail ? `Relay agent ${agentName} failed to stay online:
15110
15348
  ${stderrTail}` : `Relay agent ${agentName} failed to stay online.`);
@@ -15159,6 +15397,7 @@ async function startLocalAgent(input) {
15159
15397
  const preferredHarness = input.harness ? normalizeLocalAgentHarness(input.harness) : undefined;
15160
15398
  const currentDirectory = input.currentDirectory ?? projectPath;
15161
15399
  const effectiveCwd = input.cwdOverride ? normalizeProjectPath(input.cwdOverride) : undefined;
15400
+ const shouldEnsureOnline = input.ensureOnline !== false;
15162
15401
  const requestedDefinitionId = input.agentName?.trim() ? normalizeAgentSelectorSegment(input.agentName.trim()) : "";
15163
15402
  if (input.agentName?.trim() && !requestedDefinitionId) {
15164
15403
  throw new Error(`Invalid agent name "${input.agentName}".`);
@@ -15206,7 +15445,7 @@ async function startLocalAgent(input) {
15206
15445
  }
15207
15446
  if (!matchingOverride) {
15208
15447
  const configDefinitionId = coldProjectConfig?.agent?.id?.trim() ? normalizeAgentSelectorSegment(coldProjectConfig.agent.id.trim()) : "";
15209
- const definitionId = requestedDefinitionId || configDefinitionId || normalizeAgentSelectorSegment(basename4(projectRoot)) || "agent";
15448
+ const definitionId = requestedDefinitionId || configDefinitionId || normalizeAgentSelectorSegment(basename5(projectRoot)) || "agent";
15210
15449
  const configDisplayName = coldProjectConfig?.agent?.displayName?.trim() || "";
15211
15450
  const effectiveDisplayName = input.displayName || configDisplayName || titleCaseLocalAgentName(definitionId);
15212
15451
  const instance = buildRelayAgentInstance(definitionId, projectRoot);
@@ -15223,7 +15462,7 @@ async function startLocalAgent(input) {
15223
15462
  agentId: instance.id,
15224
15463
  definitionId,
15225
15464
  displayName: effectiveDisplayName,
15226
- projectName: basename4(projectRoot),
15465
+ projectName: basename5(projectRoot),
15227
15466
  projectRoot,
15228
15467
  projectConfigPath: coldProjectConfigPath,
15229
15468
  source: "manual",
@@ -15263,7 +15502,7 @@ async function startLocalAgent(input) {
15263
15502
  agentId: instance.id,
15264
15503
  definitionId: requestedDefinitionId,
15265
15504
  displayName: input.displayName || titleCaseLocalAgentName(requestedDefinitionId),
15266
- projectName: matchingOverride.projectName ?? basename4(matchingProjectRoot),
15505
+ projectName: matchingOverride.projectName ?? basename5(matchingProjectRoot),
15267
15506
  projectRoot: matchingProjectRoot,
15268
15507
  projectConfigPath: matchingOverride.projectConfigPath ?? null,
15269
15508
  source: "manual",
@@ -15308,12 +15547,14 @@ async function startLocalAgent(input) {
15308
15547
  }
15309
15548
  targetAgentId = matchingAgentId;
15310
15549
  }
15311
- await ensureLocalAgentBindingOnline(targetAgentId, process.env.OPENSCOUT_NODE_ID ?? "local", {
15312
- includeDiscovered: false,
15313
- currentDirectory,
15314
- ensureCurrentProjectConfig: false,
15315
- harness: preferredHarness
15316
- });
15550
+ if (shouldEnsureOnline) {
15551
+ await ensureLocalAgentBindingOnline(targetAgentId, process.env.OPENSCOUT_NODE_ID ?? "local", {
15552
+ includeDiscovered: false,
15553
+ currentDirectory,
15554
+ ensureCurrentProjectConfig: false,
15555
+ harness: preferredHarness
15556
+ });
15557
+ }
15317
15558
  const finalOverrides = await readRelayAgentOverrides();
15318
15559
  const finalOverride = finalOverrides[targetAgentId];
15319
15560
  if (!finalOverride) {
@@ -15379,8 +15620,8 @@ async function interruptLocalAgent(agentId) {
15379
15620
  function readPersistedClaudeSessionId(agentName) {
15380
15621
  try {
15381
15622
  const runtimeDir = relayAgentRuntimeDirectory(agentName);
15382
- const catalogPath = join15(runtimeDir, "session-catalog.json");
15383
- if (existsSync13(catalogPath)) {
15623
+ const catalogPath = join16(runtimeDir, "session-catalog.json");
15624
+ if (existsSync14(catalogPath)) {
15384
15625
  const raw = readFileSync8(catalogPath, "utf8").trim();
15385
15626
  if (raw) {
15386
15627
  const catalog = JSON.parse(raw);
@@ -15389,8 +15630,8 @@ function readPersistedClaudeSessionId(agentName) {
15389
15630
  }
15390
15631
  }
15391
15632
  }
15392
- const legacyPath = join15(runtimeDir, "claude-session-id.txt");
15393
- if (existsSync13(legacyPath)) {
15633
+ const legacyPath = join16(runtimeDir, "claude-session-id.txt");
15634
+ if (existsSync14(legacyPath)) {
15394
15635
  const value = readFileSync8(legacyPath, "utf8").trim();
15395
15636
  return value || null;
15396
15637
  }
@@ -15584,6 +15825,7 @@ var scoutBrokerPaths = {
15584
15825
  endpoints: "/v1/endpoints",
15585
15826
  conversations: "/v1/conversations",
15586
15827
  invocations: "/v1/invocations",
15828
+ deliver: "/v1/deliver",
15587
15829
  activity: "/v1/activity",
15588
15830
  collaborationRecords: "/v1/collaboration/records",
15589
15831
  collaborationEvents: "/v1/collaboration/events"
@@ -15613,29 +15855,6 @@ function titleCaseName(value) {
15613
15855
  function displayNameForBrokerActor(snapshot, actorId) {
15614
15856
  return snapshot.agents[actorId]?.displayName ?? snapshot.actors[actorId]?.displayName ?? titleCaseName(metadataString2(snapshot.agents[actorId]?.metadata, "definitionId") || actorId);
15615
15857
  }
15616
- function firstEndpointForActor(snapshot, actorId) {
15617
- return Object.values(snapshot.endpoints).filter((endpoint) => endpoint.agentId === actorId).sort((lhs, rhs) => lhs.id.localeCompare(rhs.id))[0];
15618
- }
15619
- function buildScoutReturnAddress2(snapshot, actorId, options = {}) {
15620
- const agent = snapshot.agents[actorId];
15621
- const actor = snapshot.actors[actorId];
15622
- const endpoint = firstEndpointForActor(snapshot, actorId);
15623
- const selector = agent?.selector?.trim() || metadataString2(agent?.metadata, "selector") || metadataString2(actor?.metadata, "selector");
15624
- const defaultSelector = agent?.defaultSelector?.trim() || metadataString2(agent?.metadata, "defaultSelector") || metadataString2(actor?.metadata, "defaultSelector");
15625
- const projectRoot = endpoint?.projectRoot ?? endpoint?.cwd ?? metadataString2(agent?.metadata, "projectRoot") ?? metadataString2(actor?.metadata, "projectRoot");
15626
- return buildScoutReturnAddress({
15627
- actorId,
15628
- handle: agent?.handle?.trim() || actor?.handle?.trim() || actorId,
15629
- displayName: agent?.displayName || actor?.displayName,
15630
- selector,
15631
- defaultSelector,
15632
- conversationId: options.conversationId,
15633
- replyToMessageId: options.replyToMessageId,
15634
- nodeId: endpoint?.nodeId || agent?.authorityNodeId || agent?.homeNodeId,
15635
- projectRoot,
15636
- sessionId: endpoint?.sessionId
15637
- });
15638
- }
15639
15858
  function metadataString2(metadata, key) {
15640
15859
  const value = metadata?.[key];
15641
15860
  return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
@@ -15938,74 +16157,42 @@ async function openScoutPeerSession(input) {
15938
16157
  };
15939
16158
  }
15940
16159
  async function sendScoutDirectMessage(input) {
15941
- const currentDirectory = input.currentDirectory ?? process.cwd();
15942
- const directSession = await openScoutPeerSession({
15943
- sourceId: OPERATOR_ID,
15944
- targetId: input.agentId,
15945
- currentDirectory
15946
- });
15947
16160
  const broker = await requireScoutBrokerContext();
15948
16161
  const createdAt = Date.now();
15949
- const messageId = `msg-${createdAt.toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
15950
16162
  const source = input.source?.trim() || "scout-mobile";
15951
- const targetAgentId = directSession.targetId;
15952
- const targetAgent = broker.snapshot.agents[targetAgentId] ?? ("agent" in directSession ? directSession.agent : undefined);
15953
- const targetLabel = `@${targetAgent?.handle?.trim() || targetAgent?.displayName?.trim() || targetAgentId}`;
15954
- const returnAddress = buildScoutReturnAddress2(broker.snapshot, OPERATOR_ID, {
15955
- conversationId: directSession.conversation.id,
15956
- replyToMessageId: messageId
15957
- });
15958
- await brokerPostJson(broker.baseUrl, scoutBrokerPaths.v1.messages, {
15959
- id: messageId,
15960
- conversationId: directSession.conversation.id,
15961
- replyToMessageId: input.replyToMessageId ?? undefined,
15962
- actorId: OPERATOR_ID,
15963
- originNodeId: broker.node.id,
15964
- class: "agent",
16163
+ const delivery = await brokerPostJson(broker.baseUrl, scoutBrokerPaths.v1.deliver, {
16164
+ id: `deliver-${createdAt.toString(36)}-${Math.random().toString(36).slice(2, 8)}`,
16165
+ requesterId: OPERATOR_ID,
16166
+ requesterNodeId: broker.node.id,
16167
+ targetAgentId: input.agentId,
15965
16168
  body: input.body.trim(),
15966
- mentions: [{ actorId: targetAgentId, label: targetLabel }],
15967
- audience: {
15968
- notify: [targetAgentId],
15969
- reason: "direct_message"
15970
- },
15971
- visibility: "private",
15972
- policy: "durable",
16169
+ intent: "consult",
16170
+ replyToMessageId: input.replyToMessageId ?? undefined,
16171
+ execution: input.executionHarness ? { harness: input.executionHarness } : undefined,
16172
+ ensureAwake: true,
15973
16173
  createdAt,
15974
- metadata: {
16174
+ messageMetadata: {
15975
16175
  source,
15976
16176
  destinationKind: "direct",
15977
- destinationId: targetAgentId,
16177
+ destinationId: input.agentId,
15978
16178
  referenceMessageIds: input.referenceMessageIds ?? [],
15979
16179
  clientMessageId: input.clientMessageId ?? null,
15980
- returnAddress,
15981
16180
  ...input.deviceId ? { deviceId: input.deviceId } : {}
15982
- }
15983
- });
15984
- const invocationResponse = await brokerPostJson(broker.baseUrl, scoutBrokerPaths.v1.invocations, {
15985
- id: `inv-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`,
15986
- requesterId: OPERATOR_ID,
15987
- requesterNodeId: broker.node.id,
15988
- targetAgentId,
15989
- action: "consult",
15990
- task: input.body.trim(),
15991
- conversationId: directSession.conversation.id,
15992
- messageId,
15993
- execution: input.executionHarness ? { harness: input.executionHarness } : undefined,
15994
- ensureAwake: true,
15995
- stream: false,
15996
- createdAt,
15997
- metadata: {
16181
+ },
16182
+ invocationMetadata: {
15998
16183
  source,
15999
16184
  destinationKind: "direct",
16000
- destinationId: targetAgentId,
16001
- returnAddress,
16185
+ destinationId: input.agentId,
16002
16186
  ...input.deviceId ? { deviceId: input.deviceId } : {}
16003
16187
  }
16004
16188
  });
16189
+ if (delivery.kind !== "delivery") {
16190
+ throw new Error(delivery.kind === "question" ? delivery.question.detail : delivery.rejection.detail);
16191
+ }
16005
16192
  return {
16006
- conversationId: directSession.conversation.id,
16007
- messageId,
16008
- flight: invocationResponse.flight
16193
+ conversationId: delivery.conversation.id,
16194
+ messageId: delivery.message.id,
16195
+ flight: delivery.flight
16009
16196
  };
16010
16197
  }
16011
16198
  async function loadScoutActivityItems(options = {}) {
@@ -16032,11 +16219,11 @@ async function upScoutAgent(input) {
16032
16219
 
16033
16220
  // ../../apps/desktop/src/server/db-queries.ts
16034
16221
  import { Database } from "bun:sqlite";
16035
- import { homedir as homedir14 } from "os";
16036
- import { join as join16 } from "path";
16222
+ import { homedir as homedir15 } from "os";
16223
+ import { join as join17 } from "path";
16037
16224
  function resolveDbPath() {
16038
- const controlHome = process.env.OPENSCOUT_CONTROL_HOME ?? join16(homedir14(), ".openscout", "control-plane");
16039
- return join16(controlHome, "control-plane.sqlite");
16225
+ const controlHome = process.env.OPENSCOUT_CONTROL_HOME ?? join17(homedir15(), ".openscout", "control-plane");
16226
+ return join17(controlHome, "control-plane.sqlite");
16040
16227
  }
16041
16228
  var _db = null;
16042
16229
  function db() {
@@ -16047,7 +16234,7 @@ function db() {
16047
16234
  }
16048
16235
  return _db;
16049
16236
  }
16050
- var HOME = homedir14();
16237
+ var HOME = homedir15();
16051
16238
  function compact(p) {
16052
16239
  if (!p)
16053
16240
  return null;
@@ -16703,8 +16890,8 @@ async function createScoutSession(input, currentDirectory, deviceId) {
16703
16890
  if (!rawWorkspaceId) {
16704
16891
  throw new Error(`Invalid workspaceId.`);
16705
16892
  }
16706
- const workspaceRoot = resolve6(rawWorkspaceId);
16707
- const projectName = basename5(workspaceRoot) || workspaceRoot;
16893
+ const workspaceRoot = resolve7(rawWorkspaceId);
16894
+ const projectName = basename6(workspaceRoot) || workspaceRoot;
16708
16895
  const workspace = {
16709
16896
  id: workspaceRoot,
16710
16897
  title: projectName,
@@ -16813,17 +17000,17 @@ async function deriveNewAgentName(projectName, branch, harness) {
16813
17000
  }
16814
17001
  async function createGitWorktree(projectRoot, agentName) {
16815
17002
  const { execSync: execSync3 } = await import("child_process");
16816
- const { join: join17 } = await import("path");
16817
- const { mkdirSync: mkdirSync9, existsSync: existsSync14 } = await import("fs");
17003
+ const { join: join18 } = await import("path");
17004
+ const { mkdirSync: mkdirSync9, existsSync: existsSync15 } = await import("fs");
16818
17005
  try {
16819
17006
  execSync3("git rev-parse --git-dir", { cwd: projectRoot, stdio: "pipe" });
16820
17007
  } catch {
16821
17008
  return null;
16822
17009
  }
16823
17010
  const branchName = `scout/${agentName}`;
16824
- const worktreeDir = join17(projectRoot, ".scout-worktrees");
16825
- const worktreePath = join17(worktreeDir, agentName);
16826
- if (existsSync14(worktreePath)) {
17011
+ const worktreeDir = join18(projectRoot, ".scout-worktrees");
17012
+ const worktreePath = join18(worktreeDir, agentName);
17013
+ if (existsSync15(worktreePath)) {
16827
17014
  return { path: worktreePath, branch: branchName };
16828
17015
  }
16829
17016
  mkdirSync9(worktreeDir, { recursive: true });
@@ -17027,9 +17214,9 @@ async function handleRPCInner(bridge, req, deviceId) {
17027
17214
  }
17028
17215
  case "session/resume": {
17029
17216
  const p = req.params;
17030
- const sessionFilename = basename6(p.sessionPath, ".jsonl");
17217
+ const sessionFilename = basename7(p.sessionPath, ".jsonl");
17031
17218
  const parentDir = p.sessionPath.substring(0, p.sessionPath.lastIndexOf("/"));
17032
- const dirName = basename6(parentDir);
17219
+ const dirName = basename7(parentDir);
17033
17220
  let cwd;
17034
17221
  if (dirName.startsWith("-")) {
17035
17222
  const candidate = "/" + dirName.slice(1).replace(/-/g, "/");
@@ -17096,7 +17283,7 @@ async function handleRPCInner(bridge, req, deviceId) {
17096
17283
  return { id: req.id, error: { code: -32000, message: "Workspace target is not a directory" } };
17097
17284
  }
17098
17285
  const adapterType = p.adapter ?? "claude-code";
17099
- const name = p.name ?? basename6(projectPath);
17286
+ const name = p.name ?? basename7(projectPath);
17100
17287
  const session = await bridge.createSession(adapterType, {
17101
17288
  name,
17102
17289
  cwd: projectPath
@@ -17336,13 +17523,13 @@ function resolveMobileCurrentDirectory() {
17336
17523
  }
17337
17524
  }
17338
17525
  function resolveWorkspaceRoot(root) {
17339
- const expandedRoot = root.replace(/^~/, homedir15());
17526
+ const expandedRoot = root.replace(/^~/, homedir16());
17340
17527
  return realpathSync(expandedRoot);
17341
17528
  }
17342
17529
  function resolveWorkspacePath(root, requestedPath) {
17343
17530
  const normalizedRoot = resolveWorkspaceRoot(root);
17344
- const expandedPath = requestedPath?.replace(/^~/, homedir15());
17345
- const candidate = expandedPath ? isAbsolute3(expandedPath) ? expandedPath : join17(normalizedRoot, expandedPath) : normalizedRoot;
17531
+ const expandedPath = requestedPath?.replace(/^~/, homedir16());
17532
+ const candidate = expandedPath ? isAbsolute3(expandedPath) ? expandedPath : join18(normalizedRoot, expandedPath) : normalizedRoot;
17346
17533
  const resolvedCandidate = realpathSync(candidate);
17347
17534
  const rel = relative2(normalizedRoot, resolvedCandidate);
17348
17535
  if (rel === "" || !rel.startsWith("..") && !isAbsolute3(rel)) {
@@ -17372,7 +17559,7 @@ function listDirectories(dirPath) {
17372
17559
  continue;
17373
17560
  if (name === "node_modules" || name === ".build" || name === "target")
17374
17561
  continue;
17375
- const fullPath = join17(dirPath, name);
17562
+ const fullPath = join18(dirPath, name);
17376
17563
  try {
17377
17564
  const stat4 = statSync3(fullPath);
17378
17565
  if (!stat4.isDirectory())
@@ -17395,7 +17582,7 @@ function listDirectories(dirPath) {
17395
17582
  return entries.sort((a, b) => a.name.localeCompare(b.name));
17396
17583
  }
17397
17584
  async function discoverSessionFiles(maxAgeDays, limit) {
17398
- const home = homedir15();
17585
+ const home = homedir16();
17399
17586
  const results = [];
17400
17587
  const searchPaths = [
17401
17588
  { pattern: `${home}/.claude/projects`, agent: "claude-code" },
@@ -31932,2189 +32119,12 @@ function date4(params) {
31932
32119
 
31933
32120
  // ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/classic/external.js
31934
32121
  config(en_default());
31935
- // ../runtime/src/registry.ts
31936
- function createRuntimeRegistrySnapshot(value = {}) {
31937
- return {
31938
- nodes: value.nodes ?? {},
31939
- actors: value.actors ?? {},
31940
- agents: value.agents ?? {},
31941
- endpoints: value.endpoints ?? {},
31942
- conversations: value.conversations ?? {},
31943
- bindings: value.bindings ?? {},
31944
- messages: value.messages ?? {},
31945
- flights: value.flights ?? {},
31946
- collaborationRecords: value.collaborationRecords ?? {}
31947
- };
31948
- }
31949
- // ../runtime/src/planner.ts
31950
- function createDeliveryId(messageId, targetId, reason, transport) {
31951
- return `del-${messageId}-${targetId}-${reason}-${transport}`;
31952
- }
31953
- function unique(values) {
31954
- return [...new Set(values)];
31955
- }
31956
- function resolveVisibilityAudience(message, conversation) {
31957
- if (message.audience?.visibleTo?.length) {
31958
- return unique(message.audience.visibleTo);
31959
- }
31960
- return unique(conversation.participantIds.filter((participantId) => participantId !== message.actorId));
31961
- }
31962
- function resolveNotifyAudience(message) {
31963
- const fromMentions = (message.mentions ?? []).map((mention) => mention.actorId);
31964
- const explicit = message.audience?.notify ?? [];
31965
- return unique([...fromMentions, ...explicit].filter((actorId) => actorId !== message.actorId));
31966
- }
31967
- function resolveInvocationAudience(message) {
31968
- return unique((message.audience?.invoke ?? []).filter((actorId) => actorId !== message.actorId));
31969
- }
31970
- function planTargetDelivery(message, route2, reason, policy) {
31971
- return {
31972
- id: createDeliveryId(message.id, route2.targetId, reason, route2.transport),
31973
- messageId: message.id,
31974
- targetId: route2.targetId,
31975
- targetNodeId: route2.nodeId,
31976
- targetKind: route2.targetKind,
31977
- transport: route2.transport,
31978
- reason,
31979
- policy,
31980
- status: "pending",
31981
- bindingId: route2.bindingId
31982
- };
31983
- }
31984
- function planMessageDeliveries(input) {
31985
- const visibilityIds = new Set(resolveVisibilityAudience(input.message, input.conversation));
31986
- const notifyIds = new Set(resolveNotifyAudience(input.message));
31987
- const invokeIds = new Set(resolveInvocationAudience(input.message));
31988
- const deliveries2 = new Map;
31989
- for (const route2 of input.participantRoutes) {
31990
- if (visibilityIds.has(route2.targetId)) {
31991
- const intent = planTargetDelivery(input.message, {
31992
- ...route2,
31993
- transport: route2.nodeId && input.localNodeId && route2.nodeId !== input.localNodeId ? "peer_broker" : route2.transport
31994
- }, input.conversation.kind === "direct" || input.conversation.kind === "group_direct" ? "direct_message" : "conversation_visibility", "durable");
31995
- deliveries2.set(intent.id, intent);
31996
- }
31997
- if (notifyIds.has(route2.targetId)) {
31998
- const intent = planTargetDelivery(input.message, {
31999
- ...route2,
32000
- transport: route2.nodeId && input.localNodeId && route2.nodeId !== input.localNodeId ? "peer_broker" : route2.transport
32001
- }, "mention", "must_ack");
32002
- deliveries2.set(intent.id, intent);
32003
- }
32004
- if (invokeIds.has(route2.targetId)) {
32005
- const intent = planTargetDelivery(input.message, {
32006
- ...route2,
32007
- transport: route2.nodeId && input.localNodeId && route2.nodeId !== input.localNodeId ? "peer_broker" : route2.transport
32008
- }, "invocation", "must_ack");
32009
- deliveries2.set(intent.id, intent);
32010
- }
32011
- if (input.message.speech?.text && route2.speechEnabled) {
32012
- const speechIntent = planTargetDelivery(input.message, {
32013
- ...route2,
32014
- transport: route2.transport === "local_socket" ? "native_voice" : "tts",
32015
- targetKind: route2.targetKind === "device" ? "voice_session" : route2.targetKind
32016
- }, "speech", "best_effort");
32017
- deliveries2.set(speechIntent.id, speechIntent);
32018
- }
32019
- }
32020
- for (const route2 of input.bindingRoutes ?? []) {
32021
- const intent = planTargetDelivery(input.message, route2, "bridge_outbound", "durable");
32022
- deliveries2.set(intent.id, intent);
32023
- }
32024
- return [...deliveries2.values()];
32025
- }
32026
- // ../../node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/entity.js
32027
- var entityKind = Symbol.for("drizzle:entityKind");
32028
- var hasOwnEntityKind = Symbol.for("drizzle:hasOwnEntityKind");
32029
- function is(value, type) {
32030
- if (!value || typeof value !== "object") {
32031
- return false;
32032
- }
32033
- if (value instanceof type) {
32034
- return true;
32035
- }
32036
- if (!Object.prototype.hasOwnProperty.call(type, entityKind)) {
32037
- throw new Error(`Class "${type.name ?? "<unknown>"}" doesn't look like a Drizzle entity. If this is incorrect and the class is provided by Drizzle, please report this as a bug.`);
32038
- }
32039
- let cls = Object.getPrototypeOf(value).constructor;
32040
- if (cls) {
32041
- while (cls) {
32042
- if (entityKind in cls && cls[entityKind] === type[entityKind]) {
32043
- return true;
32044
- }
32045
- cls = Object.getPrototypeOf(cls);
32046
- }
32047
- }
32048
- return false;
32049
- }
32050
-
32051
- // ../../node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/column.js
32052
- class Column {
32053
- constructor(table, config2) {
32054
- this.table = table;
32055
- this.config = config2;
32056
- this.name = config2.name;
32057
- this.keyAsName = config2.keyAsName;
32058
- this.notNull = config2.notNull;
32059
- this.default = config2.default;
32060
- this.defaultFn = config2.defaultFn;
32061
- this.onUpdateFn = config2.onUpdateFn;
32062
- this.hasDefault = config2.hasDefault;
32063
- this.primary = config2.primaryKey;
32064
- this.isUnique = config2.isUnique;
32065
- this.uniqueName = config2.uniqueName;
32066
- this.uniqueType = config2.uniqueType;
32067
- this.dataType = config2.dataType;
32068
- this.columnType = config2.columnType;
32069
- this.generated = config2.generated;
32070
- this.generatedIdentity = config2.generatedIdentity;
32071
- }
32072
- static [entityKind] = "Column";
32073
- name;
32074
- keyAsName;
32075
- primary;
32076
- notNull;
32077
- default;
32078
- defaultFn;
32079
- onUpdateFn;
32080
- hasDefault;
32081
- isUnique;
32082
- uniqueName;
32083
- uniqueType;
32084
- dataType;
32085
- columnType;
32086
- enumValues = undefined;
32087
- generated = undefined;
32088
- generatedIdentity = undefined;
32089
- config;
32090
- mapFromDriverValue(value) {
32091
- return value;
32092
- }
32093
- mapToDriverValue(value) {
32094
- return value;
32095
- }
32096
- shouldDisableInsert() {
32097
- return this.config.generated !== undefined && this.config.generated.type !== "byDefault";
32098
- }
32099
- }
32100
-
32101
- // ../../node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/column-builder.js
32102
- class ColumnBuilder {
32103
- static [entityKind] = "ColumnBuilder";
32104
- config;
32105
- constructor(name, dataType, columnType) {
32106
- this.config = {
32107
- name,
32108
- keyAsName: name === "",
32109
- notNull: false,
32110
- default: undefined,
32111
- hasDefault: false,
32112
- primaryKey: false,
32113
- isUnique: false,
32114
- uniqueName: undefined,
32115
- uniqueType: undefined,
32116
- dataType,
32117
- columnType,
32118
- generated: undefined
32119
- };
32120
- }
32121
- $type() {
32122
- return this;
32123
- }
32124
- notNull() {
32125
- this.config.notNull = true;
32126
- return this;
32127
- }
32128
- default(value) {
32129
- this.config.default = value;
32130
- this.config.hasDefault = true;
32131
- return this;
32132
- }
32133
- $defaultFn(fn) {
32134
- this.config.defaultFn = fn;
32135
- this.config.hasDefault = true;
32136
- return this;
32137
- }
32138
- $default = this.$defaultFn;
32139
- $onUpdateFn(fn) {
32140
- this.config.onUpdateFn = fn;
32141
- this.config.hasDefault = true;
32142
- return this;
32143
- }
32144
- $onUpdate = this.$onUpdateFn;
32145
- primaryKey() {
32146
- this.config.primaryKey = true;
32147
- this.config.notNull = true;
32148
- return this;
32149
- }
32150
- setName(name) {
32151
- if (this.config.name !== "")
32152
- return;
32153
- this.config.name = name;
32154
- }
32155
- }
32156
-
32157
- // ../../node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/table.utils.js
32158
- var TableName = Symbol.for("drizzle:Name");
32159
-
32160
- // ../../node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/tracing-utils.js
32161
- function iife(fn, ...args) {
32162
- return fn(...args);
32163
- }
32164
-
32165
- // ../../node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/pg-core/unique-constraint.js
32166
- function uniqueKeyName(table, columns) {
32167
- return `${table[TableName]}_${columns.join("_")}_unique`;
32168
- }
32169
-
32170
- // ../../node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/pg-core/columns/common.js
32171
- class PgColumn extends Column {
32172
- constructor(table, config2) {
32173
- if (!config2.uniqueName) {
32174
- config2.uniqueName = uniqueKeyName(table, [config2.name]);
32175
- }
32176
- super(table, config2);
32177
- this.table = table;
32178
- }
32179
- static [entityKind] = "PgColumn";
32180
- }
32181
-
32182
- class ExtraConfigColumn extends PgColumn {
32183
- static [entityKind] = "ExtraConfigColumn";
32184
- getSQLType() {
32185
- return this.getSQLType();
32186
- }
32187
- indexConfig = {
32188
- order: this.config.order ?? "asc",
32189
- nulls: this.config.nulls ?? "last",
32190
- opClass: this.config.opClass
32191
- };
32192
- defaultConfig = {
32193
- order: "asc",
32194
- nulls: "last",
32195
- opClass: undefined
32196
- };
32197
- asc() {
32198
- this.indexConfig.order = "asc";
32199
- return this;
32200
- }
32201
- desc() {
32202
- this.indexConfig.order = "desc";
32203
- return this;
32204
- }
32205
- nullsFirst() {
32206
- this.indexConfig.nulls = "first";
32207
- return this;
32208
- }
32209
- nullsLast() {
32210
- this.indexConfig.nulls = "last";
32211
- return this;
32212
- }
32213
- op(opClass) {
32214
- this.indexConfig.opClass = opClass;
32215
- return this;
32216
- }
32217
- }
32218
-
32219
- // ../../node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/pg-core/columns/enum.js
32220
- class PgEnumObjectColumn extends PgColumn {
32221
- static [entityKind] = "PgEnumObjectColumn";
32222
- enum;
32223
- enumValues = this.config.enum.enumValues;
32224
- constructor(table, config2) {
32225
- super(table, config2);
32226
- this.enum = config2.enum;
32227
- }
32228
- getSQLType() {
32229
- return this.enum.enumName;
32230
- }
32231
- }
32232
- var isPgEnumSym = Symbol.for("drizzle:isPgEnum");
32233
- function isPgEnum(obj) {
32234
- return !!obj && typeof obj === "function" && isPgEnumSym in obj && obj[isPgEnumSym] === true;
32235
- }
32236
- class PgEnumColumn extends PgColumn {
32237
- static [entityKind] = "PgEnumColumn";
32238
- enum = this.config.enum;
32239
- enumValues = this.config.enum.enumValues;
32240
- constructor(table, config2) {
32241
- super(table, config2);
32242
- this.enum = config2.enum;
32243
- }
32244
- getSQLType() {
32245
- return this.enum.enumName;
32246
- }
32247
- }
32248
-
32249
- // ../../node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/subquery.js
32250
- class Subquery {
32251
- static [entityKind] = "Subquery";
32252
- constructor(sql, fields, alias, isWith = false, usedTables = []) {
32253
- this._ = {
32254
- brand: "Subquery",
32255
- sql,
32256
- selectedFields: fields,
32257
- alias,
32258
- isWith,
32259
- usedTables
32260
- };
32261
- }
32262
- }
32263
-
32264
- // ../../node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/version.js
32265
- var version2 = "0.45.2";
32266
-
32267
- // ../../node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/tracing.js
32268
- var otel;
32269
- var rawTracer;
32270
- var tracer = {
32271
- startActiveSpan(name, fn) {
32272
- if (!otel) {
32273
- return fn();
32274
- }
32275
- if (!rawTracer) {
32276
- rawTracer = otel.trace.getTracer("drizzle-orm", version2);
32277
- }
32278
- return iife((otel2, rawTracer2) => rawTracer2.startActiveSpan(name, (span) => {
32279
- try {
32280
- return fn(span);
32281
- } catch (e) {
32282
- span.setStatus({
32283
- code: otel2.SpanStatusCode.ERROR,
32284
- message: e instanceof Error ? e.message : "Unknown error"
32285
- });
32286
- throw e;
32287
- } finally {
32288
- span.end();
32289
- }
32290
- }), otel, rawTracer);
32291
- }
32292
- };
32293
-
32294
- // ../../node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/view-common.js
32295
- var ViewBaseConfig = Symbol.for("drizzle:ViewBaseConfig");
32296
-
32297
- // ../../node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/table.js
32298
- var Schema = Symbol.for("drizzle:Schema");
32299
- var Columns = Symbol.for("drizzle:Columns");
32300
- var ExtraConfigColumns = Symbol.for("drizzle:ExtraConfigColumns");
32301
- var OriginalName = Symbol.for("drizzle:OriginalName");
32302
- var BaseName = Symbol.for("drizzle:BaseName");
32303
- var IsAlias = Symbol.for("drizzle:IsAlias");
32304
- var ExtraConfigBuilder = Symbol.for("drizzle:ExtraConfigBuilder");
32305
- var IsDrizzleTable = Symbol.for("drizzle:IsDrizzleTable");
32306
-
32307
- class Table {
32308
- static [entityKind] = "Table";
32309
- static Symbol = {
32310
- Name: TableName,
32311
- Schema,
32312
- OriginalName,
32313
- Columns,
32314
- ExtraConfigColumns,
32315
- BaseName,
32316
- IsAlias,
32317
- ExtraConfigBuilder
32318
- };
32319
- [TableName];
32320
- [OriginalName];
32321
- [Schema];
32322
- [Columns];
32323
- [ExtraConfigColumns];
32324
- [BaseName];
32325
- [IsAlias] = false;
32326
- [IsDrizzleTable] = true;
32327
- [ExtraConfigBuilder] = undefined;
32328
- constructor(name, schema, baseName) {
32329
- this[TableName] = this[OriginalName] = name;
32330
- this[Schema] = schema;
32331
- this[BaseName] = baseName;
32332
- }
32333
- }
32334
-
32335
- // ../../node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/sql/sql.js
32336
- function isSQLWrapper(value) {
32337
- return value !== null && value !== undefined && typeof value.getSQL === "function";
32338
- }
32339
- function mergeQueries(queries) {
32340
- const result = { sql: "", params: [] };
32341
- for (const query of queries) {
32342
- result.sql += query.sql;
32343
- result.params.push(...query.params);
32344
- if (query.typings?.length) {
32345
- if (!result.typings) {
32346
- result.typings = [];
32347
- }
32348
- result.typings.push(...query.typings);
32349
- }
32350
- }
32351
- return result;
32352
- }
32353
-
32354
- class StringChunk {
32355
- static [entityKind] = "StringChunk";
32356
- value;
32357
- constructor(value) {
32358
- this.value = Array.isArray(value) ? value : [value];
32359
- }
32360
- getSQL() {
32361
- return new SQL([this]);
32362
- }
32363
- }
32364
-
32365
- class SQL {
32366
- constructor(queryChunks) {
32367
- this.queryChunks = queryChunks;
32368
- for (const chunk of queryChunks) {
32369
- if (is(chunk, Table)) {
32370
- const schemaName = chunk[Table.Symbol.Schema];
32371
- this.usedTables.push(schemaName === undefined ? chunk[Table.Symbol.Name] : schemaName + "." + chunk[Table.Symbol.Name]);
32372
- }
32373
- }
32374
- }
32375
- static [entityKind] = "SQL";
32376
- decoder = noopDecoder;
32377
- shouldInlineParams = false;
32378
- usedTables = [];
32379
- append(query) {
32380
- this.queryChunks.push(...query.queryChunks);
32381
- return this;
32382
- }
32383
- toQuery(config2) {
32384
- return tracer.startActiveSpan("drizzle.buildSQL", (span) => {
32385
- const query = this.buildQueryFromSourceParams(this.queryChunks, config2);
32386
- span?.setAttributes({
32387
- "drizzle.query.text": query.sql,
32388
- "drizzle.query.params": JSON.stringify(query.params)
32389
- });
32390
- return query;
32391
- });
32392
- }
32393
- buildQueryFromSourceParams(chunks, _config) {
32394
- const config2 = Object.assign({}, _config, {
32395
- inlineParams: _config.inlineParams || this.shouldInlineParams,
32396
- paramStartIndex: _config.paramStartIndex || { value: 0 }
32397
- });
32398
- const {
32399
- casing,
32400
- escapeName,
32401
- escapeParam,
32402
- prepareTyping,
32403
- inlineParams,
32404
- paramStartIndex
32405
- } = config2;
32406
- return mergeQueries(chunks.map((chunk) => {
32407
- if (is(chunk, StringChunk)) {
32408
- return { sql: chunk.value.join(""), params: [] };
32409
- }
32410
- if (is(chunk, Name)) {
32411
- return { sql: escapeName(chunk.value), params: [] };
32412
- }
32413
- if (chunk === undefined) {
32414
- return { sql: "", params: [] };
32415
- }
32416
- if (Array.isArray(chunk)) {
32417
- const result = [new StringChunk("(")];
32418
- for (const [i, p] of chunk.entries()) {
32419
- result.push(p);
32420
- if (i < chunk.length - 1) {
32421
- result.push(new StringChunk(", "));
32422
- }
32423
- }
32424
- result.push(new StringChunk(")"));
32425
- return this.buildQueryFromSourceParams(result, config2);
32426
- }
32427
- if (is(chunk, SQL)) {
32428
- return this.buildQueryFromSourceParams(chunk.queryChunks, {
32429
- ...config2,
32430
- inlineParams: inlineParams || chunk.shouldInlineParams
32431
- });
32432
- }
32433
- if (is(chunk, Table)) {
32434
- const schemaName = chunk[Table.Symbol.Schema];
32435
- const tableName = chunk[Table.Symbol.Name];
32436
- return {
32437
- sql: schemaName === undefined || chunk[IsAlias] ? escapeName(tableName) : escapeName(schemaName) + "." + escapeName(tableName),
32438
- params: []
32439
- };
32440
- }
32441
- if (is(chunk, Column)) {
32442
- const columnName = casing.getColumnCasing(chunk);
32443
- if (_config.invokeSource === "indexes") {
32444
- return { sql: escapeName(columnName), params: [] };
32445
- }
32446
- const schemaName = chunk.table[Table.Symbol.Schema];
32447
- return {
32448
- sql: chunk.table[IsAlias] || schemaName === undefined ? escapeName(chunk.table[Table.Symbol.Name]) + "." + escapeName(columnName) : escapeName(schemaName) + "." + escapeName(chunk.table[Table.Symbol.Name]) + "." + escapeName(columnName),
32449
- params: []
32450
- };
32451
- }
32452
- if (is(chunk, View)) {
32453
- const schemaName = chunk[ViewBaseConfig].schema;
32454
- const viewName = chunk[ViewBaseConfig].name;
32455
- return {
32456
- sql: schemaName === undefined || chunk[ViewBaseConfig].isAlias ? escapeName(viewName) : escapeName(schemaName) + "." + escapeName(viewName),
32457
- params: []
32458
- };
32459
- }
32460
- if (is(chunk, Param)) {
32461
- if (is(chunk.value, Placeholder)) {
32462
- return { sql: escapeParam(paramStartIndex.value++, chunk), params: [chunk], typings: ["none"] };
32463
- }
32464
- const mappedValue = chunk.value === null ? null : chunk.encoder.mapToDriverValue(chunk.value);
32465
- if (is(mappedValue, SQL)) {
32466
- return this.buildQueryFromSourceParams([mappedValue], config2);
32467
- }
32468
- if (inlineParams) {
32469
- return { sql: this.mapInlineParam(mappedValue, config2), params: [] };
32470
- }
32471
- let typings = ["none"];
32472
- if (prepareTyping) {
32473
- typings = [prepareTyping(chunk.encoder)];
32474
- }
32475
- return { sql: escapeParam(paramStartIndex.value++, mappedValue), params: [mappedValue], typings };
32476
- }
32477
- if (is(chunk, Placeholder)) {
32478
- return { sql: escapeParam(paramStartIndex.value++, chunk), params: [chunk], typings: ["none"] };
32479
- }
32480
- if (is(chunk, SQL.Aliased) && chunk.fieldAlias !== undefined) {
32481
- return { sql: escapeName(chunk.fieldAlias), params: [] };
32482
- }
32483
- if (is(chunk, Subquery)) {
32484
- if (chunk._.isWith) {
32485
- return { sql: escapeName(chunk._.alias), params: [] };
32486
- }
32487
- return this.buildQueryFromSourceParams([
32488
- new StringChunk("("),
32489
- chunk._.sql,
32490
- new StringChunk(") "),
32491
- new Name(chunk._.alias)
32492
- ], config2);
32493
- }
32494
- if (isPgEnum(chunk)) {
32495
- if (chunk.schema) {
32496
- return { sql: escapeName(chunk.schema) + "." + escapeName(chunk.enumName), params: [] };
32497
- }
32498
- return { sql: escapeName(chunk.enumName), params: [] };
32499
- }
32500
- if (isSQLWrapper(chunk)) {
32501
- if (chunk.shouldOmitSQLParens?.()) {
32502
- return this.buildQueryFromSourceParams([chunk.getSQL()], config2);
32503
- }
32504
- return this.buildQueryFromSourceParams([
32505
- new StringChunk("("),
32506
- chunk.getSQL(),
32507
- new StringChunk(")")
32508
- ], config2);
32509
- }
32510
- if (inlineParams) {
32511
- return { sql: this.mapInlineParam(chunk, config2), params: [] };
32512
- }
32513
- return { sql: escapeParam(paramStartIndex.value++, chunk), params: [chunk], typings: ["none"] };
32514
- }));
32515
- }
32516
- mapInlineParam(chunk, { escapeString }) {
32517
- if (chunk === null) {
32518
- return "null";
32519
- }
32520
- if (typeof chunk === "number" || typeof chunk === "boolean") {
32521
- return chunk.toString();
32522
- }
32523
- if (typeof chunk === "string") {
32524
- return escapeString(chunk);
32525
- }
32526
- if (typeof chunk === "object") {
32527
- const mappedValueAsString = chunk.toString();
32528
- if (mappedValueAsString === "[object Object]") {
32529
- return escapeString(JSON.stringify(chunk));
32530
- }
32531
- return escapeString(mappedValueAsString);
32532
- }
32533
- throw new Error("Unexpected param value: " + chunk);
32534
- }
32535
- getSQL() {
32536
- return this;
32537
- }
32538
- as(alias) {
32539
- if (alias === undefined) {
32540
- return this;
32541
- }
32542
- return new SQL.Aliased(this, alias);
32543
- }
32544
- mapWith(decoder) {
32545
- this.decoder = typeof decoder === "function" ? { mapFromDriverValue: decoder } : decoder;
32546
- return this;
32547
- }
32548
- inlineParams() {
32549
- this.shouldInlineParams = true;
32550
- return this;
32551
- }
32552
- if(condition) {
32553
- return condition ? this : undefined;
32554
- }
32555
- }
32556
-
32557
- class Name {
32558
- constructor(value) {
32559
- this.value = value;
32560
- }
32561
- static [entityKind] = "Name";
32562
- brand;
32563
- getSQL() {
32564
- return new SQL([this]);
32565
- }
32566
- }
32567
- var noopDecoder = {
32568
- mapFromDriverValue: (value) => value
32569
- };
32570
- var noopEncoder = {
32571
- mapToDriverValue: (value) => value
32572
- };
32573
- var noopMapper = {
32574
- ...noopDecoder,
32575
- ...noopEncoder
32576
- };
32577
-
32578
- class Param {
32579
- constructor(value, encoder = noopEncoder) {
32580
- this.value = value;
32581
- this.encoder = encoder;
32582
- }
32583
- static [entityKind] = "Param";
32584
- brand;
32585
- getSQL() {
32586
- return new SQL([this]);
32587
- }
32588
- }
32589
- function sql(strings, ...params) {
32590
- const queryChunks = [];
32591
- if (params.length > 0 || strings.length > 0 && strings[0] !== "") {
32592
- queryChunks.push(new StringChunk(strings[0]));
32593
- }
32594
- for (const [paramIndex, param2] of params.entries()) {
32595
- queryChunks.push(param2, new StringChunk(strings[paramIndex + 1]));
32596
- }
32597
- return new SQL(queryChunks);
32598
- }
32599
- ((sql2) => {
32600
- function empty() {
32601
- return new SQL([]);
32602
- }
32603
- sql2.empty = empty;
32604
- function fromList(list) {
32605
- return new SQL(list);
32606
- }
32607
- sql2.fromList = fromList;
32608
- function raw(str) {
32609
- return new SQL([new StringChunk(str)]);
32610
- }
32611
- sql2.raw = raw;
32612
- function join18(chunks, separator) {
32613
- const result = [];
32614
- for (const [i, chunk] of chunks.entries()) {
32615
- if (i > 0 && separator !== undefined) {
32616
- result.push(separator);
32617
- }
32618
- result.push(chunk);
32619
- }
32620
- return new SQL(result);
32621
- }
32622
- sql2.join = join18;
32623
- function identifier(value) {
32624
- return new Name(value);
32625
- }
32626
- sql2.identifier = identifier;
32627
- function placeholder2(name2) {
32628
- return new Placeholder(name2);
32629
- }
32630
- sql2.placeholder = placeholder2;
32631
- function param2(value, encoder) {
32632
- return new Param(value, encoder);
32633
- }
32634
- sql2.param = param2;
32635
- })(sql || (sql = {}));
32636
- ((SQL2) => {
32637
-
32638
- class Aliased {
32639
- constructor(sql2, fieldAlias) {
32640
- this.sql = sql2;
32641
- this.fieldAlias = fieldAlias;
32642
- }
32643
- static [entityKind] = "SQL.Aliased";
32644
- isSelectionField = false;
32645
- getSQL() {
32646
- return this.sql;
32647
- }
32648
- clone() {
32649
- return new Aliased(this.sql, this.fieldAlias);
32650
- }
32651
- }
32652
- SQL2.Aliased = Aliased;
32653
- })(SQL || (SQL = {}));
32654
-
32655
- class Placeholder {
32656
- constructor(name2) {
32657
- this.name = name2;
32658
- }
32659
- static [entityKind] = "Placeholder";
32660
- getSQL() {
32661
- return new SQL([this]);
32662
- }
32663
- }
32664
- var IsDrizzleView = Symbol.for("drizzle:IsDrizzleView");
32665
-
32666
- class View {
32667
- static [entityKind] = "View";
32668
- [ViewBaseConfig];
32669
- [IsDrizzleView] = true;
32670
- constructor({ name: name2, schema, selectedFields, query }) {
32671
- this[ViewBaseConfig] = {
32672
- name: name2,
32673
- originalName: name2,
32674
- schema,
32675
- selectedFields,
32676
- query,
32677
- isExisting: !query,
32678
- isAlias: false
32679
- };
32680
- }
32681
- getSQL() {
32682
- return new SQL([this]);
32683
- }
32684
- }
32685
- Column.prototype.getSQL = function() {
32686
- return new SQL([this]);
32687
- };
32688
- Table.prototype.getSQL = function() {
32689
- return new SQL([this]);
32690
- };
32691
- Subquery.prototype.getSQL = function() {
32692
- return new SQL([this]);
32693
- };
32694
-
32695
- // ../../node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/utils.js
32696
- function getColumnNameAndConfig(a, b) {
32697
- return {
32698
- name: typeof a === "string" && a.length > 0 ? a : "",
32699
- config: typeof a === "object" ? a : b
32700
- };
32701
- }
32702
- var textDecoder = typeof TextDecoder === "undefined" ? null : new TextDecoder;
32703
-
32704
- // ../../node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/sqlite-core/foreign-keys.js
32705
- class ForeignKeyBuilder {
32706
- static [entityKind] = "SQLiteForeignKeyBuilder";
32707
- reference;
32708
- _onUpdate;
32709
- _onDelete;
32710
- constructor(config2, actions) {
32711
- this.reference = () => {
32712
- const { name, columns, foreignColumns } = config2();
32713
- return { name, columns, foreignTable: foreignColumns[0].table, foreignColumns };
32714
- };
32715
- if (actions) {
32716
- this._onUpdate = actions.onUpdate;
32717
- this._onDelete = actions.onDelete;
32718
- }
32719
- }
32720
- onUpdate(action) {
32721
- this._onUpdate = action;
32722
- return this;
32723
- }
32724
- onDelete(action) {
32725
- this._onDelete = action;
32726
- return this;
32727
- }
32728
- build(table) {
32729
- return new ForeignKey(table, this);
32730
- }
32731
- }
32732
-
32733
- class ForeignKey {
32734
- constructor(table, builder) {
32735
- this.table = table;
32736
- this.reference = builder.reference;
32737
- this.onUpdate = builder._onUpdate;
32738
- this.onDelete = builder._onDelete;
32739
- }
32740
- static [entityKind] = "SQLiteForeignKey";
32741
- reference;
32742
- onUpdate;
32743
- onDelete;
32744
- getName() {
32745
- const { name, columns, foreignColumns } = this.reference();
32746
- const columnNames = columns.map((column) => column.name);
32747
- const foreignColumnNames = foreignColumns.map((column) => column.name);
32748
- const chunks = [
32749
- this.table[TableName],
32750
- ...columnNames,
32751
- foreignColumns[0].table[TableName],
32752
- ...foreignColumnNames
32753
- ];
32754
- return name ?? `${chunks.join("_")}_fk`;
32755
- }
32756
- }
32757
-
32758
- // ../../node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/sqlite-core/unique-constraint.js
32759
- function uniqueKeyName2(table, columns) {
32760
- return `${table[TableName]}_${columns.join("_")}_unique`;
32761
- }
32762
-
32763
- // ../../node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/sqlite-core/columns/common.js
32764
- class SQLiteColumnBuilder extends ColumnBuilder {
32765
- static [entityKind] = "SQLiteColumnBuilder";
32766
- foreignKeyConfigs = [];
32767
- references(ref, actions = {}) {
32768
- this.foreignKeyConfigs.push({ ref, actions });
32769
- return this;
32770
- }
32771
- unique(name) {
32772
- this.config.isUnique = true;
32773
- this.config.uniqueName = name;
32774
- return this;
32775
- }
32776
- generatedAlwaysAs(as, config2) {
32777
- this.config.generated = {
32778
- as,
32779
- type: "always",
32780
- mode: config2?.mode ?? "virtual"
32781
- };
32782
- return this;
32783
- }
32784
- buildForeignKeys(column, table) {
32785
- return this.foreignKeyConfigs.map(({ ref, actions }) => {
32786
- return ((ref2, actions2) => {
32787
- const builder = new ForeignKeyBuilder(() => {
32788
- const foreignColumn = ref2();
32789
- return { columns: [column], foreignColumns: [foreignColumn] };
32790
- });
32791
- if (actions2.onUpdate) {
32792
- builder.onUpdate(actions2.onUpdate);
32793
- }
32794
- if (actions2.onDelete) {
32795
- builder.onDelete(actions2.onDelete);
32796
- }
32797
- return builder.build(table);
32798
- })(ref, actions);
32799
- });
32800
- }
32801
- }
32802
-
32803
- class SQLiteColumn extends Column {
32804
- constructor(table, config2) {
32805
- if (!config2.uniqueName) {
32806
- config2.uniqueName = uniqueKeyName2(table, [config2.name]);
32807
- }
32808
- super(table, config2);
32809
- this.table = table;
32810
- }
32811
- static [entityKind] = "SQLiteColumn";
32812
- }
32813
-
32814
- // ../../node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/sqlite-core/columns/blob.js
32815
- class SQLiteBigIntBuilder extends SQLiteColumnBuilder {
32816
- static [entityKind] = "SQLiteBigIntBuilder";
32817
- constructor(name) {
32818
- super(name, "bigint", "SQLiteBigInt");
32819
- }
32820
- build(table) {
32821
- return new SQLiteBigInt(table, this.config);
32822
- }
32823
- }
32824
-
32825
- class SQLiteBigInt extends SQLiteColumn {
32826
- static [entityKind] = "SQLiteBigInt";
32827
- getSQLType() {
32828
- return "blob";
32829
- }
32830
- mapFromDriverValue(value) {
32831
- if (typeof Buffer !== "undefined" && Buffer.from) {
32832
- const buf = Buffer.isBuffer(value) ? value : value instanceof ArrayBuffer ? Buffer.from(value) : value.buffer ? Buffer.from(value.buffer, value.byteOffset, value.byteLength) : Buffer.from(value);
32833
- return BigInt(buf.toString("utf8"));
32834
- }
32835
- return BigInt(textDecoder.decode(value));
32836
- }
32837
- mapToDriverValue(value) {
32838
- return Buffer.from(value.toString());
32839
- }
32840
- }
32841
-
32842
- class SQLiteBlobJsonBuilder extends SQLiteColumnBuilder {
32843
- static [entityKind] = "SQLiteBlobJsonBuilder";
32844
- constructor(name) {
32845
- super(name, "json", "SQLiteBlobJson");
32846
- }
32847
- build(table) {
32848
- return new SQLiteBlobJson(table, this.config);
32849
- }
32850
- }
32851
-
32852
- class SQLiteBlobJson extends SQLiteColumn {
32853
- static [entityKind] = "SQLiteBlobJson";
32854
- getSQLType() {
32855
- return "blob";
32856
- }
32857
- mapFromDriverValue(value) {
32858
- if (typeof Buffer !== "undefined" && Buffer.from) {
32859
- const buf = Buffer.isBuffer(value) ? value : value instanceof ArrayBuffer ? Buffer.from(value) : value.buffer ? Buffer.from(value.buffer, value.byteOffset, value.byteLength) : Buffer.from(value);
32860
- return JSON.parse(buf.toString("utf8"));
32861
- }
32862
- return JSON.parse(textDecoder.decode(value));
32863
- }
32864
- mapToDriverValue(value) {
32865
- return Buffer.from(JSON.stringify(value));
32866
- }
32867
- }
32868
-
32869
- class SQLiteBlobBufferBuilder extends SQLiteColumnBuilder {
32870
- static [entityKind] = "SQLiteBlobBufferBuilder";
32871
- constructor(name) {
32872
- super(name, "buffer", "SQLiteBlobBuffer");
32873
- }
32874
- build(table) {
32875
- return new SQLiteBlobBuffer(table, this.config);
32876
- }
32877
- }
32878
-
32879
- class SQLiteBlobBuffer extends SQLiteColumn {
32880
- static [entityKind] = "SQLiteBlobBuffer";
32881
- mapFromDriverValue(value) {
32882
- if (Buffer.isBuffer(value)) {
32883
- return value;
32884
- }
32885
- return Buffer.from(value);
32886
- }
32887
- getSQLType() {
32888
- return "blob";
32889
- }
32890
- }
32891
- function blob(a, b) {
32892
- const { name, config: config2 } = getColumnNameAndConfig(a, b);
32893
- if (config2?.mode === "json") {
32894
- return new SQLiteBlobJsonBuilder(name);
32895
- }
32896
- if (config2?.mode === "bigint") {
32897
- return new SQLiteBigIntBuilder(name);
32898
- }
32899
- return new SQLiteBlobBufferBuilder(name);
32900
- }
32901
-
32902
- // ../../node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/sqlite-core/columns/custom.js
32903
- class SQLiteCustomColumnBuilder extends SQLiteColumnBuilder {
32904
- static [entityKind] = "SQLiteCustomColumnBuilder";
32905
- constructor(name, fieldConfig, customTypeParams) {
32906
- super(name, "custom", "SQLiteCustomColumn");
32907
- this.config.fieldConfig = fieldConfig;
32908
- this.config.customTypeParams = customTypeParams;
32909
- }
32910
- build(table) {
32911
- return new SQLiteCustomColumn(table, this.config);
32912
- }
32913
- }
32914
-
32915
- class SQLiteCustomColumn extends SQLiteColumn {
32916
- static [entityKind] = "SQLiteCustomColumn";
32917
- sqlName;
32918
- mapTo;
32919
- mapFrom;
32920
- constructor(table, config2) {
32921
- super(table, config2);
32922
- this.sqlName = config2.customTypeParams.dataType(config2.fieldConfig);
32923
- this.mapTo = config2.customTypeParams.toDriver;
32924
- this.mapFrom = config2.customTypeParams.fromDriver;
32925
- }
32926
- getSQLType() {
32927
- return this.sqlName;
32928
- }
32929
- mapFromDriverValue(value) {
32930
- return typeof this.mapFrom === "function" ? this.mapFrom(value) : value;
32931
- }
32932
- mapToDriverValue(value) {
32933
- return typeof this.mapTo === "function" ? this.mapTo(value) : value;
32934
- }
32935
- }
32936
- function customType(customTypeParams) {
32937
- return (a, b) => {
32938
- const { name, config: config2 } = getColumnNameAndConfig(a, b);
32939
- return new SQLiteCustomColumnBuilder(name, config2, customTypeParams);
32940
- };
32941
- }
32942
-
32943
- // ../../node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/sqlite-core/columns/integer.js
32944
- class SQLiteBaseIntegerBuilder extends SQLiteColumnBuilder {
32945
- static [entityKind] = "SQLiteBaseIntegerBuilder";
32946
- constructor(name, dataType, columnType) {
32947
- super(name, dataType, columnType);
32948
- this.config.autoIncrement = false;
32949
- }
32950
- primaryKey(config2) {
32951
- if (config2?.autoIncrement) {
32952
- this.config.autoIncrement = true;
32953
- }
32954
- this.config.hasDefault = true;
32955
- return super.primaryKey();
32956
- }
32957
- }
32958
-
32959
- class SQLiteBaseInteger extends SQLiteColumn {
32960
- static [entityKind] = "SQLiteBaseInteger";
32961
- autoIncrement = this.config.autoIncrement;
32962
- getSQLType() {
32963
- return "integer";
32964
- }
32965
- }
32966
-
32967
- class SQLiteIntegerBuilder extends SQLiteBaseIntegerBuilder {
32968
- static [entityKind] = "SQLiteIntegerBuilder";
32969
- constructor(name) {
32970
- super(name, "number", "SQLiteInteger");
32971
- }
32972
- build(table) {
32973
- return new SQLiteInteger(table, this.config);
32974
- }
32975
- }
32976
-
32977
- class SQLiteInteger extends SQLiteBaseInteger {
32978
- static [entityKind] = "SQLiteInteger";
32979
- }
32980
-
32981
- class SQLiteTimestampBuilder extends SQLiteBaseIntegerBuilder {
32982
- static [entityKind] = "SQLiteTimestampBuilder";
32983
- constructor(name, mode) {
32984
- super(name, "date", "SQLiteTimestamp");
32985
- this.config.mode = mode;
32986
- }
32987
- defaultNow() {
32988
- return this.default(sql`(cast((julianday('now') - 2440587.5)*86400000 as integer))`);
32989
- }
32990
- build(table) {
32991
- return new SQLiteTimestamp(table, this.config);
32992
- }
32993
- }
32994
-
32995
- class SQLiteTimestamp extends SQLiteBaseInteger {
32996
- static [entityKind] = "SQLiteTimestamp";
32997
- mode = this.config.mode;
32998
- mapFromDriverValue(value) {
32999
- if (this.config.mode === "timestamp") {
33000
- return new Date(value * 1000);
33001
- }
33002
- return new Date(value);
33003
- }
33004
- mapToDriverValue(value) {
33005
- const unix = value.getTime();
33006
- if (this.config.mode === "timestamp") {
33007
- return Math.floor(unix / 1000);
33008
- }
33009
- return unix;
33010
- }
33011
- }
33012
-
33013
- class SQLiteBooleanBuilder extends SQLiteBaseIntegerBuilder {
33014
- static [entityKind] = "SQLiteBooleanBuilder";
33015
- constructor(name, mode) {
33016
- super(name, "boolean", "SQLiteBoolean");
33017
- this.config.mode = mode;
33018
- }
33019
- build(table) {
33020
- return new SQLiteBoolean(table, this.config);
33021
- }
33022
- }
33023
-
33024
- class SQLiteBoolean extends SQLiteBaseInteger {
33025
- static [entityKind] = "SQLiteBoolean";
33026
- mode = this.config.mode;
33027
- mapFromDriverValue(value) {
33028
- return Number(value) === 1;
33029
- }
33030
- mapToDriverValue(value) {
33031
- return value ? 1 : 0;
33032
- }
33033
- }
33034
- function integer2(a, b) {
33035
- const { name, config: config2 } = getColumnNameAndConfig(a, b);
33036
- if (config2?.mode === "timestamp" || config2?.mode === "timestamp_ms") {
33037
- return new SQLiteTimestampBuilder(name, config2.mode);
33038
- }
33039
- if (config2?.mode === "boolean") {
33040
- return new SQLiteBooleanBuilder(name, config2.mode);
33041
- }
33042
- return new SQLiteIntegerBuilder(name);
33043
- }
33044
-
33045
- // ../../node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/sqlite-core/columns/numeric.js
33046
- class SQLiteNumericBuilder extends SQLiteColumnBuilder {
33047
- static [entityKind] = "SQLiteNumericBuilder";
33048
- constructor(name) {
33049
- super(name, "string", "SQLiteNumeric");
33050
- }
33051
- build(table) {
33052
- return new SQLiteNumeric(table, this.config);
33053
- }
33054
- }
33055
-
33056
- class SQLiteNumeric extends SQLiteColumn {
33057
- static [entityKind] = "SQLiteNumeric";
33058
- mapFromDriverValue(value) {
33059
- if (typeof value === "string")
33060
- return value;
33061
- return String(value);
33062
- }
33063
- getSQLType() {
33064
- return "numeric";
33065
- }
33066
- }
33067
-
33068
- class SQLiteNumericNumberBuilder extends SQLiteColumnBuilder {
33069
- static [entityKind] = "SQLiteNumericNumberBuilder";
33070
- constructor(name) {
33071
- super(name, "number", "SQLiteNumericNumber");
33072
- }
33073
- build(table) {
33074
- return new SQLiteNumericNumber(table, this.config);
33075
- }
33076
- }
33077
-
33078
- class SQLiteNumericNumber extends SQLiteColumn {
33079
- static [entityKind] = "SQLiteNumericNumber";
33080
- mapFromDriverValue(value) {
33081
- if (typeof value === "number")
33082
- return value;
33083
- return Number(value);
33084
- }
33085
- mapToDriverValue = String;
33086
- getSQLType() {
33087
- return "numeric";
33088
- }
33089
- }
33090
-
33091
- class SQLiteNumericBigIntBuilder extends SQLiteColumnBuilder {
33092
- static [entityKind] = "SQLiteNumericBigIntBuilder";
33093
- constructor(name) {
33094
- super(name, "bigint", "SQLiteNumericBigInt");
33095
- }
33096
- build(table) {
33097
- return new SQLiteNumericBigInt(table, this.config);
33098
- }
33099
- }
33100
-
33101
- class SQLiteNumericBigInt extends SQLiteColumn {
33102
- static [entityKind] = "SQLiteNumericBigInt";
33103
- mapFromDriverValue = BigInt;
33104
- mapToDriverValue = String;
33105
- getSQLType() {
33106
- return "numeric";
33107
- }
33108
- }
33109
- function numeric(a, b) {
33110
- const { name, config: config2 } = getColumnNameAndConfig(a, b);
33111
- const mode = config2?.mode;
33112
- return mode === "number" ? new SQLiteNumericNumberBuilder(name) : mode === "bigint" ? new SQLiteNumericBigIntBuilder(name) : new SQLiteNumericBuilder(name);
33113
- }
33114
-
33115
- // ../../node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/sqlite-core/columns/real.js
33116
- class SQLiteRealBuilder extends SQLiteColumnBuilder {
33117
- static [entityKind] = "SQLiteRealBuilder";
33118
- constructor(name) {
33119
- super(name, "number", "SQLiteReal");
33120
- }
33121
- build(table) {
33122
- return new SQLiteReal(table, this.config);
33123
- }
33124
- }
33125
-
33126
- class SQLiteReal extends SQLiteColumn {
33127
- static [entityKind] = "SQLiteReal";
33128
- getSQLType() {
33129
- return "real";
33130
- }
33131
- }
33132
- function real(name) {
33133
- return new SQLiteRealBuilder(name ?? "");
33134
- }
33135
-
33136
- // ../../node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/sqlite-core/columns/text.js
33137
- class SQLiteTextBuilder extends SQLiteColumnBuilder {
33138
- static [entityKind] = "SQLiteTextBuilder";
33139
- constructor(name, config2) {
33140
- super(name, "string", "SQLiteText");
33141
- this.config.enumValues = config2.enum;
33142
- this.config.length = config2.length;
33143
- }
33144
- build(table) {
33145
- return new SQLiteText(table, this.config);
33146
- }
33147
- }
33148
-
33149
- class SQLiteText extends SQLiteColumn {
33150
- static [entityKind] = "SQLiteText";
33151
- enumValues = this.config.enumValues;
33152
- length = this.config.length;
33153
- constructor(table, config2) {
33154
- super(table, config2);
33155
- }
33156
- getSQLType() {
33157
- return `text${this.config.length ? `(${this.config.length})` : ""}`;
33158
- }
33159
- }
33160
-
33161
- class SQLiteTextJsonBuilder extends SQLiteColumnBuilder {
33162
- static [entityKind] = "SQLiteTextJsonBuilder";
33163
- constructor(name) {
33164
- super(name, "json", "SQLiteTextJson");
33165
- }
33166
- build(table) {
33167
- return new SQLiteTextJson(table, this.config);
33168
- }
33169
- }
33170
-
33171
- class SQLiteTextJson extends SQLiteColumn {
33172
- static [entityKind] = "SQLiteTextJson";
33173
- getSQLType() {
33174
- return "text";
33175
- }
33176
- mapFromDriverValue(value) {
33177
- return JSON.parse(value);
33178
- }
33179
- mapToDriverValue(value) {
33180
- return JSON.stringify(value);
33181
- }
33182
- }
33183
- function text(a, b = {}) {
33184
- const { name, config: config2 } = getColumnNameAndConfig(a, b);
33185
- if (config2.mode === "json") {
33186
- return new SQLiteTextJsonBuilder(name);
33187
- }
33188
- return new SQLiteTextBuilder(name, config2);
33189
- }
33190
-
33191
- // ../../node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/sqlite-core/columns/all.js
33192
- function getSQLiteColumnBuilders() {
33193
- return {
33194
- blob,
33195
- customType,
33196
- integer: integer2,
33197
- numeric,
33198
- real,
33199
- text
33200
- };
33201
- }
33202
-
33203
- // ../../node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/sqlite-core/table.js
33204
- var InlineForeignKeys = Symbol.for("drizzle:SQLiteInlineForeignKeys");
33205
-
33206
- class SQLiteTable extends Table {
33207
- static [entityKind] = "SQLiteTable";
33208
- static Symbol = Object.assign({}, Table.Symbol, {
33209
- InlineForeignKeys
33210
- });
33211
- [Table.Symbol.Columns];
33212
- [InlineForeignKeys] = [];
33213
- [Table.Symbol.ExtraConfigBuilder] = undefined;
33214
- }
33215
- function sqliteTableBase(name, columns, extraConfig, schema, baseName = name) {
33216
- const rawTable = new SQLiteTable(name, schema, baseName);
33217
- const parsedColumns = typeof columns === "function" ? columns(getSQLiteColumnBuilders()) : columns;
33218
- const builtColumns = Object.fromEntries(Object.entries(parsedColumns).map(([name2, colBuilderBase]) => {
33219
- const colBuilder = colBuilderBase;
33220
- colBuilder.setName(name2);
33221
- const column = colBuilder.build(rawTable);
33222
- rawTable[InlineForeignKeys].push(...colBuilder.buildForeignKeys(column, rawTable));
33223
- return [name2, column];
33224
- }));
33225
- const table = Object.assign(rawTable, builtColumns);
33226
- table[Table.Symbol.Columns] = builtColumns;
33227
- table[Table.Symbol.ExtraConfigColumns] = builtColumns;
33228
- if (extraConfig) {
33229
- table[SQLiteTable.Symbol.ExtraConfigBuilder] = extraConfig;
33230
- }
33231
- return table;
33232
- }
33233
- var sqliteTable = (name, columns, extraConfig) => {
33234
- return sqliteTableBase(name, columns, extraConfig);
33235
- };
33236
-
33237
- // ../../node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/sqlite-core/indexes.js
33238
- class IndexBuilderOn {
33239
- constructor(name, unique2) {
33240
- this.name = name;
33241
- this.unique = unique2;
33242
- }
33243
- static [entityKind] = "SQLiteIndexBuilderOn";
33244
- on(...columns) {
33245
- return new IndexBuilder(this.name, columns, this.unique);
33246
- }
33247
- }
33248
-
33249
- class IndexBuilder {
33250
- static [entityKind] = "SQLiteIndexBuilder";
33251
- config;
33252
- constructor(name, columns, unique2) {
33253
- this.config = {
33254
- name,
33255
- columns,
33256
- unique: unique2,
33257
- where: undefined
33258
- };
33259
- }
33260
- where(condition) {
33261
- this.config.where = condition;
33262
- return this;
33263
- }
33264
- build(table) {
33265
- return new Index(this.config, table);
33266
- }
33267
- }
33268
-
33269
- class Index {
33270
- static [entityKind] = "SQLiteIndex";
33271
- config;
33272
- constructor(config2, table) {
33273
- this.config = { ...config2, table };
33274
- }
33275
- }
33276
- function index(name) {
33277
- return new IndexBuilderOn(name, false);
33278
- }
33279
-
33280
- // ../runtime/src/drizzle-schema.ts
33281
- var deliveriesTable = sqliteTable("deliveries", {
33282
- id: text("id").primaryKey(),
33283
- messageId: text("message_id"),
33284
- invocationId: text("invocation_id"),
33285
- targetId: text("target_id").notNull(),
33286
- targetNodeId: text("target_node_id"),
33287
- targetKind: text("target_kind").$type().notNull(),
33288
- transport: text("transport").$type().notNull(),
33289
- reason: text("reason").$type().notNull(),
33290
- policy: text("policy").$type().notNull(),
33291
- status: text("status").$type().notNull(),
33292
- bindingId: text("binding_id"),
33293
- leaseOwner: text("lease_owner"),
33294
- leaseExpiresAt: integer2("lease_expires_at"),
33295
- metadataJson: text("metadata_json"),
33296
- createdAt: integer2("created_at").notNull().default(sql`(unixepoch())`)
33297
- }, (table) => [
33298
- index("idx_deliveries_status_transport").on(table.status, table.transport)
33299
- ]);
33300
- var deliveryAttemptsTable = sqliteTable("delivery_attempts", {
33301
- id: text("id").primaryKey(),
33302
- deliveryId: text("delivery_id").notNull(),
33303
- attempt: integer2("attempt").notNull(),
33304
- status: text("status").$type().notNull(),
33305
- error: text("error"),
33306
- externalRef: text("external_ref"),
33307
- metadataJson: text("metadata_json"),
33308
- createdAt: integer2("created_at").notNull()
33309
- });
33310
- // ../runtime/src/broker.ts
33311
- function createRuntimeId(prefix) {
33312
- return `${prefix}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
33313
- }
33314
- function toTargetKind(actor) {
33315
- if (!actor)
33316
- return "participant";
33317
- if (actor.kind === "agent")
33318
- return "agent";
33319
- if (actor.kind === "device")
33320
- return "device";
33321
- if (actor.kind === "bridge")
33322
- return "bridge";
33323
- return "participant";
33324
- }
33325
- function defaultTransportForActor(actor) {
33326
- if (!actor)
33327
- return "local_socket";
33328
- switch (actor.kind) {
33329
- case "bridge":
33330
- return "webhook";
33331
- case "device":
33332
- return "local_socket";
33333
- case "agent":
33334
- return "local_socket";
33335
- default:
33336
- return "local_socket";
33337
- }
33338
- }
33339
- function endpointTransportRank(transport) {
33340
- switch (transport) {
33341
- case "codex_app_server":
33342
- return 0;
33343
- case "claude_stream_json":
33344
- return 1;
33345
- case "tmux":
33346
- return 2;
33347
- case "local_socket":
33348
- return 3;
33349
- default:
33350
- return 4;
33351
- }
33352
- }
33353
- function shouldBridgeMessageToBinding(binding, message) {
33354
- if (binding.platform !== "telegram") {
33355
- return true;
33356
- }
33357
- const source = typeof message.metadata?.source === "string" ? String(message.metadata.source) : "";
33358
- if (source === "telegram") {
33359
- return false;
33360
- }
33361
- const outboundMode = typeof binding.metadata?.outboundMode === "string" ? String(binding.metadata.outboundMode) : "operator_only";
33362
- const operatorId = typeof binding.metadata?.operatorId === "string" ? String(binding.metadata.operatorId) : "operator";
33363
- const allowedActorIds = Array.isArray(binding.metadata?.allowedActorIds) ? binding.metadata.allowedActorIds.map((entry) => String(entry).trim()).filter(Boolean) : [];
33364
- if (outboundMode === "all") {
33365
- return true;
33366
- }
33367
- if (outboundMode === "allowlist") {
33368
- return allowedActorIds.includes(message.actorId);
33369
- }
33370
- return message.actorId === operatorId;
33371
- }
33372
- function resolveBindingRoutes(bindings, message) {
33373
- return bindings.filter((binding) => shouldBridgeMessageToBinding(binding, message)).map((binding) => ({
33374
- targetId: binding.id,
33375
- targetKind: "bridge",
33376
- transport: binding.platform === "telegram" ? "telegram" : binding.platform === "discord" ? "discord" : "webhook",
33377
- bindingId: binding.id
33378
- }));
33379
- }
33380
- function preferredEndpoint(endpoints) {
33381
- let preferred;
33382
- let preferredRank = Number.POSITIVE_INFINITY;
33383
- for (const endpoint of endpoints) {
33384
- const rank = endpointTransportRank(endpoint.transport);
33385
- if (!preferred || rank < preferredRank) {
33386
- preferred = endpoint;
33387
- preferredRank = rank;
33388
- }
33389
- }
33390
- return preferred;
33391
- }
33392
-
33393
- class InMemoryControlRuntime {
33394
- registry;
33395
- listeners = new Set;
33396
- eventBuffer = [];
33397
- localNodeId;
33398
- endpointIdsByAgentId = new Map;
33399
- bindingIdsByConversationId = new Map;
33400
- flightIdByInvocationId = new Map;
33401
- constructor(initial = {}, options = {}) {
33402
- this.registry = createRuntimeRegistrySnapshot(initial);
33403
- this.localNodeId = options.localNodeId;
33404
- this.rebuildIndexes();
33405
- }
33406
- snapshot() {
33407
- return createRuntimeRegistrySnapshot({
33408
- nodes: { ...this.registry.nodes },
33409
- actors: { ...this.registry.actors },
33410
- agents: { ...this.registry.agents },
33411
- endpoints: { ...this.registry.endpoints },
33412
- conversations: { ...this.registry.conversations },
33413
- bindings: { ...this.registry.bindings },
33414
- messages: { ...this.registry.messages },
33415
- flights: { ...this.registry.flights },
33416
- collaborationRecords: { ...this.registry.collaborationRecords }
33417
- });
33418
- }
33419
- peek() {
33420
- return this.registry;
33421
- }
33422
- node(nodeId) {
33423
- return this.registry.nodes[nodeId];
33424
- }
33425
- agent(agentId) {
33426
- return this.registry.agents[agentId];
33427
- }
33428
- conversation(conversationId) {
33429
- return this.registry.conversations[conversationId];
33430
- }
33431
- message(messageId) {
33432
- return this.registry.messages[messageId];
33433
- }
33434
- collaborationRecord(recordId) {
33435
- return this.registry.collaborationRecords[recordId];
33436
- }
33437
- flightForInvocation(invocationId) {
33438
- const flightId = this.flightIdByInvocationId.get(invocationId);
33439
- return flightId ? this.registry.flights[flightId] : undefined;
33440
- }
33441
- bindingsForConversation(conversationId) {
33442
- const bindingIds = this.bindingIdsByConversationId.get(conversationId);
33443
- if (!bindingIds) {
33444
- return [];
33445
- }
33446
- const bindings = [];
33447
- for (const bindingId of bindingIds) {
33448
- const binding = this.registry.bindings[bindingId];
33449
- if (binding) {
33450
- bindings.push(binding);
33451
- }
33452
- }
33453
- return bindings;
33454
- }
33455
- endpointsForAgent(agentId, options = {}) {
33456
- const endpointIds = this.endpointIdsByAgentId.get(agentId);
33457
- if (!endpointIds) {
33458
- return [];
33459
- }
33460
- const endpoints = [];
33461
- for (const endpointId of endpointIds) {
33462
- const endpoint = this.registry.endpoints[endpointId];
33463
- if (!endpoint)
33464
- continue;
33465
- if (!options.includeOffline && endpoint.state === "offline")
33466
- continue;
33467
- if (options.nodeId && endpoint.nodeId !== options.nodeId)
33468
- continue;
33469
- if (options.harness && endpoint.harness !== options.harness)
33470
- continue;
33471
- endpoints.push(endpoint);
33472
- }
33473
- return endpoints;
33474
- }
33475
- recentEvents(limit = 100) {
33476
- return this.eventBuffer.slice(-limit);
33477
- }
33478
- subscribe(listener) {
33479
- this.listeners.add(listener);
33480
- return () => {
33481
- this.listeners.delete(listener);
33482
- };
33483
- }
33484
- async dispatch(command) {
33485
- switch (command.kind) {
33486
- case "node.upsert":
33487
- await this.upsertNode(command.node);
33488
- return;
33489
- case "actor.upsert":
33490
- await this.upsertActor(command.actor);
33491
- return;
33492
- case "agent.upsert":
33493
- await this.upsertAgent(command.agent);
33494
- return;
33495
- case "agent.endpoint.upsert":
33496
- await this.upsertEndpoint(command.endpoint);
33497
- return;
33498
- case "conversation.upsert":
33499
- await this.upsertConversation(command.conversation);
33500
- return;
33501
- case "binding.upsert":
33502
- await this.upsertBinding(command.binding);
33503
- return;
33504
- case "collaboration.upsert":
33505
- await this.upsertCollaboration(command.record);
33506
- return;
33507
- case "collaboration.event.append":
33508
- await this.appendCollaborationEvent(command.event);
33509
- return;
33510
- case "conversation.post":
33511
- await this.postMessage(command.message);
33512
- return;
33513
- case "agent.invoke":
33514
- await this.invokeAgent(command.invocation);
33515
- return;
33516
- case "agent.ensure_awake":
33517
- this.emit({
33518
- id: createRuntimeId("evt"),
33519
- kind: "flight.updated",
33520
- ts: Date.now(),
33521
- actorId: command.requesterId,
33522
- nodeId: this.localNodeId,
33523
- payload: {
33524
- flight: {
33525
- id: createRuntimeId("flt"),
33526
- invocationId: command.agentId,
33527
- requesterId: command.requesterId,
33528
- targetAgentId: command.agentId,
33529
- state: "waking",
33530
- summary: command.reason
33531
- }
33532
- }
33533
- });
33534
- return;
33535
- case "stream.subscribe":
33536
- return;
33537
- default: {
33538
- const exhaustive = command;
33539
- return exhaustive;
33540
- }
33541
- }
33542
- }
33543
- async upsertNode(node) {
33544
- this.registry.nodes[node.id] = node;
33545
- this.emit({
33546
- id: createRuntimeId("evt"),
33547
- kind: "node.upserted",
33548
- ts: Date.now(),
33549
- actorId: node.id,
33550
- nodeId: node.id,
33551
- payload: { node }
33552
- });
33553
- }
33554
- async upsertActor(actor) {
33555
- this.registry.actors[actor.id] = {
33556
- id: actor.id,
33557
- kind: actor.kind,
33558
- displayName: actor.displayName,
33559
- handle: actor.handle,
33560
- labels: actor.labels,
33561
- metadata: actor.metadata
33562
- };
33563
- this.emit({
33564
- id: createRuntimeId("evt"),
33565
- kind: "actor.registered",
33566
- ts: Date.now(),
33567
- actorId: actor.id,
33568
- nodeId: this.localNodeId,
33569
- payload: { actor }
33570
- });
33571
- }
33572
- async upsertAgent(agent) {
33573
- if (!this.registry.actors[agent.id]) {
33574
- this.registry.actors[agent.id] = {
33575
- id: agent.id,
33576
- kind: agent.kind,
33577
- displayName: agent.displayName,
33578
- handle: agent.handle,
33579
- labels: agent.labels,
33580
- metadata: agent.metadata
33581
- };
33582
- }
33583
- this.registry.agents[agent.id] = agent;
33584
- this.emit({
33585
- id: createRuntimeId("evt"),
33586
- kind: "agent.registered",
33587
- ts: Date.now(),
33588
- actorId: agent.id,
33589
- nodeId: agent.authorityNodeId,
33590
- payload: { agent }
33591
- });
33592
- }
33593
- async upsertEndpoint(endpoint) {
33594
- const previous = this.registry.endpoints[endpoint.id];
33595
- if (previous) {
33596
- this.unindexEndpoint(previous);
33597
- }
33598
- this.registry.endpoints[endpoint.id] = endpoint;
33599
- this.indexEndpoint(endpoint);
33600
- this.emit({
33601
- id: createRuntimeId("evt"),
33602
- kind: "agent.endpoint.upserted",
33603
- ts: Date.now(),
33604
- actorId: endpoint.agentId,
33605
- nodeId: endpoint.nodeId,
33606
- payload: { endpoint }
33607
- });
33608
- }
33609
- async upsertConversation(conversation) {
33610
- this.registry.conversations[conversation.id] = conversation;
33611
- this.emit({
33612
- id: createRuntimeId("evt"),
33613
- kind: "conversation.upserted",
33614
- ts: Date.now(),
33615
- actorId: "system",
33616
- nodeId: conversation.authorityNodeId,
33617
- payload: { conversation }
33618
- });
33619
- }
33620
- async upsertBinding(binding) {
33621
- const previous = this.registry.bindings[binding.id];
33622
- if (previous) {
33623
- this.unindexBinding(previous);
33624
- }
33625
- this.registry.bindings[binding.id] = binding;
33626
- this.indexBinding(binding);
33627
- this.emit({
33628
- id: createRuntimeId("evt"),
33629
- kind: "binding.upserted",
33630
- ts: Date.now(),
33631
- actorId: "system",
33632
- nodeId: this.localNodeId,
33633
- payload: { binding }
33634
- });
33635
- }
33636
- async upsertCollaboration(record2) {
33637
- assertValidCollaborationRecord(record2);
33638
- this.registry.collaborationRecords[record2.id] = record2;
33639
- this.emit({
33640
- id: createRuntimeId("evt"),
33641
- kind: "collaboration.upserted",
33642
- ts: Date.now(),
33643
- actorId: record2.createdById,
33644
- nodeId: this.localNodeId,
33645
- payload: { record: record2 }
33646
- });
33647
- }
33648
- async appendCollaborationEvent(event) {
33649
- const record2 = this.registry.collaborationRecords[event.recordId];
33650
- if (!record2) {
33651
- throw new Error(`unknown collaboration record: ${event.recordId}`);
33652
- }
33653
- assertValidCollaborationEvent(event, record2);
33654
- this.emit({
33655
- id: createRuntimeId("evt"),
33656
- kind: "collaboration.event.appended",
33657
- ts: Date.now(),
33658
- actorId: event.actorId,
33659
- nodeId: this.localNodeId,
33660
- payload: { event }
33661
- });
33662
- }
33663
- async upsertFlight(flight) {
33664
- const previous = this.registry.flights[flight.id];
33665
- if (previous && this.flightIdByInvocationId.get(previous.invocationId) === previous.id) {
33666
- this.flightIdByInvocationId.delete(previous.invocationId);
33667
- }
33668
- this.registry.flights[flight.id] = flight;
33669
- this.flightIdByInvocationId.set(flight.invocationId, flight.id);
33670
- this.emit({
33671
- id: createRuntimeId("evt"),
33672
- kind: "flight.updated",
33673
- ts: Date.now(),
33674
- actorId: flight.requesterId,
33675
- nodeId: this.localNodeId,
33676
- payload: { flight }
33677
- });
33678
- }
33679
- async postMessage(message, options = {}) {
33680
- const deliveries2 = this.planMessage(message, options);
33681
- await this.commitMessage(message, deliveries2);
33682
- return deliveries2;
33683
- }
33684
- planMessage(message, options = {}) {
33685
- const conversation = this.registry.conversations[message.conversationId];
33686
- if (!conversation) {
33687
- throw new Error(`unknown conversation: ${message.conversationId}`);
33688
- }
33689
- const bindingRoutes = resolveBindingRoutes(this.bindingsForConversation(conversation.id), message);
33690
- const plannedParticipantRoutes = this.resolveParticipantRoutes(conversation.participantIds);
33691
- const participantRoutes = options.localOnly ? plannedParticipantRoutes.filter((route2) => !route2.nodeId || route2.nodeId === this.localNodeId) : plannedParticipantRoutes;
33692
- const deliveries2 = planMessageDeliveries({
33693
- localNodeId: this.localNodeId,
33694
- message,
33695
- conversation,
33696
- participantRoutes,
33697
- bindingRoutes: options.localOnly ? [] : bindingRoutes
33698
- });
33699
- return deliveries2;
33700
- }
33701
- async commitMessage(message, deliveries2) {
33702
- this.registry.messages[message.id] = message;
33703
- this.emit({
33704
- id: createRuntimeId("evt"),
33705
- kind: "message.posted",
33706
- ts: Date.now(),
33707
- actorId: message.actorId,
33708
- nodeId: message.originNodeId,
33709
- payload: { message }
33710
- });
33711
- for (const delivery of deliveries2) {
33712
- this.emit({
33713
- id: createRuntimeId("evt"),
33714
- kind: "delivery.planned",
33715
- ts: Date.now(),
33716
- actorId: message.actorId,
33717
- nodeId: message.originNodeId,
33718
- payload: { delivery }
33719
- });
33720
- }
33721
- }
33722
- async invokeAgent(invocation) {
33723
- const flight = this.planInvocation(invocation);
33724
- await this.commitInvocation(invocation, flight);
33725
- return flight;
33726
- }
33727
- planInvocation(invocation) {
33728
- const targetAgent = this.registry.agents[invocation.targetAgentId];
33729
- if (!targetAgent) {
33730
- throw new Error(`unknown agent: ${invocation.targetAgentId}`);
33731
- }
33732
- const targetEndpoints = this.endpointsForAgent(invocation.targetAgentId, {
33733
- nodeId: targetAgent.authorityNodeId,
33734
- harness: invocation.execution?.harness
33735
- });
33736
- const isLocalAuthority = !this.localNodeId || targetAgent.authorityNodeId === this.localNodeId;
33737
- const startedAt = Date.now();
33738
- let state = invocation.ensureAwake ? "waking" : "queued";
33739
- let summary;
33740
- let error48;
33741
- let completedAt;
33742
- if (isLocalAuthority) {
33743
- if (targetEndpoints.length == 0) {
33744
- state = invocation.ensureAwake ? "waking" : "queued";
33745
- summary = invocation.ensureAwake ? invocation.execution?.harness ? `${targetAgent.displayName} waking on ${invocation.execution.harness}.` : `${targetAgent.displayName} waking.` : `Message stored for ${targetAgent.displayName}. Will deliver when online.`;
33746
- } else {
33747
- state = "queued";
33748
- summary = `${targetAgent.displayName} queued for local execution.`;
33749
- }
33750
- }
33751
- const flight = {
33752
- id: createRuntimeId("flt"),
33753
- invocationId: invocation.id,
33754
- requesterId: invocation.requesterId,
33755
- targetAgentId: invocation.targetAgentId,
33756
- state,
33757
- summary,
33758
- error: error48,
33759
- startedAt,
33760
- completedAt,
33761
- metadata: invocation.metadata
33762
- };
33763
- return flight;
33764
- }
33765
- async commitInvocation(invocation, flight) {
33766
- const previous = this.registry.flights[flight.id];
33767
- if (previous && this.flightIdByInvocationId.get(previous.invocationId) === previous.id) {
33768
- this.flightIdByInvocationId.delete(previous.invocationId);
33769
- }
33770
- this.registry.flights[flight.id] = flight;
33771
- this.flightIdByInvocationId.set(flight.invocationId, flight.id);
33772
- const targetAgent = this.registry.agents[invocation.targetAgentId];
33773
- this.emit({
33774
- id: createRuntimeId("evt"),
33775
- kind: "invocation.requested",
33776
- ts: Date.now(),
33777
- actorId: invocation.requesterId,
33778
- nodeId: invocation.requesterNodeId,
33779
- payload: { invocation }
33780
- });
33781
- this.emit({
33782
- id: createRuntimeId("evt"),
33783
- kind: "flight.updated",
33784
- ts: Date.now(),
33785
- actorId: invocation.requesterId,
33786
- nodeId: targetAgent?.authorityNodeId,
33787
- payload: { flight }
33788
- });
33789
- }
33790
- rebuildIndexes() {
33791
- for (const endpoint of Object.values(this.registry.endpoints)) {
33792
- this.indexEndpoint(endpoint);
33793
- }
33794
- for (const binding of Object.values(this.registry.bindings)) {
33795
- this.indexBinding(binding);
33796
- }
33797
- for (const flight of Object.values(this.registry.flights)) {
33798
- this.flightIdByInvocationId.set(flight.invocationId, flight.id);
33799
- }
33800
- }
33801
- indexEndpoint(endpoint) {
33802
- this.addIndexedId(this.endpointIdsByAgentId, endpoint.agentId, endpoint.id);
33803
- }
33804
- unindexEndpoint(endpoint) {
33805
- this.removeIndexedId(this.endpointIdsByAgentId, endpoint.agentId, endpoint.id);
33806
- }
33807
- indexBinding(binding) {
33808
- this.addIndexedId(this.bindingIdsByConversationId, binding.conversationId, binding.id);
33809
- }
33810
- unindexBinding(binding) {
33811
- this.removeIndexedId(this.bindingIdsByConversationId, binding.conversationId, binding.id);
33812
- }
33813
- addIndexedId(index2, key, value) {
33814
- const ids = index2.get(key) ?? new Set;
33815
- ids.add(value);
33816
- index2.set(key, ids);
33817
- }
33818
- removeIndexedId(index2, key, value) {
33819
- const ids = index2.get(key);
33820
- if (!ids) {
33821
- return;
33822
- }
33823
- ids.delete(value);
33824
- if (ids.size === 0) {
33825
- index2.delete(key);
33826
- }
33827
- }
33828
- resolveParticipantRoutes(participantIds) {
33829
- const routes = [];
33830
- for (const participantId of participantIds) {
33831
- const actor = this.registry.actors[participantId];
33832
- const agent = this.registry.agents[participantId];
33833
- const targetIdentity = actor ?? agent;
33834
- const endpoints = this.endpointsForAgent(participantId);
33835
- const endpoint = preferredEndpoint(endpoints);
33836
- if (!endpoint) {
33837
- if (agent?.authorityNodeId && agent.authorityNodeId !== this.localNodeId) {
33838
- routes.push({
33839
- targetId: participantId,
33840
- nodeId: agent.authorityNodeId,
33841
- targetKind: toTargetKind(targetIdentity),
33842
- transport: defaultTransportForActor(targetIdentity),
33843
- speechEnabled: false
33844
- });
33845
- } else if (agent) {
33846
- routes.push({
33847
- targetId: participantId,
33848
- nodeId: agent.authorityNodeId ?? this.localNodeId,
33849
- targetKind: toTargetKind(targetIdentity),
33850
- transport: defaultTransportForActor(targetIdentity),
33851
- speechEnabled: false
33852
- });
33853
- }
33854
- continue;
33855
- }
33856
- routes.push({
33857
- targetId: participantId,
33858
- nodeId: endpoint.nodeId ?? agent?.authorityNodeId,
33859
- targetKind: toTargetKind(targetIdentity),
33860
- transport: endpoint.transport ?? defaultTransportForActor(targetIdentity),
33861
- speechEnabled: Boolean(actor?.kind === "device" || endpoints.some((candidate) => candidate.transport === "local_socket" || candidate.transport === "websocket"))
33862
- });
33863
- }
33864
- return routes;
33865
- }
33866
- emit(event) {
33867
- this.eventBuffer.push(event);
33868
- if (this.eventBuffer.length > 500) {
33869
- this.eventBuffer.shift();
33870
- }
33871
- for (const listener of this.listeners) {
33872
- listener(event);
33873
- }
33874
- }
33875
- }
33876
- // ../runtime/src/tailscale.ts
33877
- import { execFile } from "child_process";
33878
- import { promisify } from "util";
33879
- var execFileAsync = promisify(execFile);
33880
- // ../runtime/src/thread-events.ts
33881
- class ThreadWatchProtocolError extends Error {
33882
- status;
33883
- body;
33884
- constructor(status, body) {
33885
- super(body.message);
33886
- this.status = status;
33887
- this.body = body;
33888
- }
33889
- }
33890
- function watchKey(conversationId, watcherNodeId, watcherId) {
33891
- return `${conversationId}:${watcherNodeId}:${watcherId}`;
33892
- }
33893
- function writeSse(response, eventName, payload) {
33894
- response.write(`event: ${eventName}
33895
- data: ${JSON.stringify(payload)}
33896
-
33897
- `);
33898
- }
33899
-
33900
- class ThreadEventPlane {
33901
- options;
33902
- watches = new Map;
33903
- watchIdsByKey = new Map;
33904
- watchIdsByConversation = new Map;
33905
- constructor(options) {
33906
- this.options = options;
33907
- }
33908
- async openWatch(request) {
33909
- const conversation = this.requireConversationAuthority(request.conversationId);
33910
- this.requireRemoteWatchAllowed(conversation);
33911
- const afterSeq = Math.max(0, request.afterSeq ?? 0);
33912
- const oldestSeq = await this.options.projection.oldestThreadSeq(conversation.id);
33913
- const latestSeq = await this.options.projection.latestThreadSeq(conversation.id);
33914
- if (latestSeq > 0 && oldestSeq > 0 && afterSeq < oldestSeq - 1) {
33915
- throw new ThreadWatchProtocolError(409, {
33916
- code: "cursor_out_of_range",
33917
- message: `thread cursor ${afterSeq} is older than retained seq ${oldestSeq}`
33918
- });
33919
- }
33920
- const key = watchKey(conversation.id, request.watcherNodeId, request.watcherId);
33921
- const existingWatchId = this.watchIdsByKey.get(key);
33922
- if (existingWatchId) {
33923
- this.closeWatchInternal(existingWatchId);
33924
- }
33925
- const watchId = `thread-watch:${conversation.id}:${request.watcherNodeId}:${request.watcherId}`;
33926
- const leaseExpiresAt = Date.now() + this.normalizeLeaseMs(request.leaseMs);
33927
- const watch = {
33928
- watchId,
33929
- conversationId: conversation.id,
33930
- watcherNodeId: request.watcherNodeId,
33931
- watcherId: request.watcherId,
33932
- acceptedAfterSeq: afterSeq,
33933
- leaseExpiresAt,
33934
- mode: conversation.shareMode === "summary" ? "summary" : "shared",
33935
- clients: new Set
33936
- };
33937
- this.watches.set(watchId, watch);
33938
- this.watchIdsByKey.set(key, watchId);
33939
- this.indexWatch(watch);
33940
- return {
33941
- watchId,
33942
- conversationId: conversation.id,
33943
- authorityNodeId: conversation.authorityNodeId,
33944
- acceptedAfterSeq: afterSeq,
33945
- latestSeq,
33946
- leaseExpiresAt,
33947
- mode: watch.mode
33948
- };
33949
- }
33950
- async renewWatch(request) {
33951
- const watch = this.requireLiveWatch(request.watchId);
33952
- watch.leaseExpiresAt = Date.now() + this.normalizeLeaseMs(request.leaseMs);
33953
- return {
33954
- watchId: watch.watchId,
33955
- leaseExpiresAt: watch.leaseExpiresAt
33956
- };
33957
- }
33958
- async closeWatch(request) {
33959
- this.closeWatchInternal(request.watchId);
33960
- }
33961
- async replay(options) {
33962
- const conversation = this.requireConversationAuthority(options.conversationId);
33963
- this.requireRemoteWatchAllowed(conversation);
33964
- const oldestSeq = await this.options.projection.oldestThreadSeq(conversation.id);
33965
- const latestSeq = await this.options.projection.latestThreadSeq(conversation.id);
33966
- if (latestSeq > 0 && oldestSeq > 0 && options.afterSeq < oldestSeq - 1) {
33967
- throw new ThreadWatchProtocolError(409, {
33968
- code: "cursor_out_of_range",
33969
- message: `thread cursor ${options.afterSeq} is older than retained seq ${oldestSeq}`
33970
- });
33971
- }
33972
- return this.options.projection.listThreadEvents({
33973
- conversationId: conversation.id,
33974
- afterSeq: options.afterSeq,
33975
- limit: Math.min(options.limit ?? 500, this.options.maxReplayLimit ?? 2000)
33976
- });
33977
- }
33978
- async snapshot(conversationId) {
33979
- const conversation = this.requireConversationAuthority(conversationId);
33980
- this.requireRemoteWatchAllowed(conversation);
33981
- const snapshot = await this.options.projection.getThreadSnapshot(conversation.id);
33982
- if (!snapshot) {
33983
- throw new ThreadWatchProtocolError(404, {
33984
- code: "unknown_conversation",
33985
- message: `unknown conversation ${conversation.id}`
33986
- });
33987
- }
33988
- return snapshot;
33989
- }
33990
- async streamWatch(watchId, request, response) {
33991
- const watch = this.requireLiveWatch(watchId);
33992
- const backlog = await this.options.projection.listThreadEvents({
33993
- conversationId: watch.conversationId,
33994
- afterSeq: watch.acceptedAfterSeq,
33995
- limit: this.options.maxReplayLimit ?? 2000
33996
- });
33997
- response.writeHead(200, {
33998
- "content-type": "text/event-stream",
33999
- "cache-control": "no-cache, no-transform",
34000
- connection: "keep-alive"
34001
- });
34002
- writeSse(response, "hello", {
34003
- watchId: watch.watchId,
34004
- conversationId: watch.conversationId,
34005
- leaseExpiresAt: watch.leaseExpiresAt
34006
- });
34007
- for (const event of backlog) {
34008
- writeSse(response, "thread.event", event);
34009
- }
34010
- watch.clients.add(response);
34011
- request.on("close", () => {
34012
- watch.clients.delete(response);
34013
- response.end();
34014
- });
34015
- }
34016
- publish(events2) {
34017
- for (const event of events2) {
34018
- const watchIds = this.watchIdsByConversation.get(event.conversationId);
34019
- if (!watchIds || watchIds.size === 0) {
34020
- continue;
34021
- }
34022
- for (const watchId of [...watchIds]) {
34023
- const watch = this.watches.get(watchId);
34024
- if (!watch) {
34025
- watchIds.delete(watchId);
34026
- continue;
34027
- }
34028
- if (watch.leaseExpiresAt <= Date.now()) {
34029
- this.closeWatchInternal(watchId);
34030
- continue;
34031
- }
34032
- for (const client of watch.clients) {
34033
- writeSse(client, "thread.event", event);
34034
- }
34035
- }
34036
- }
34037
- }
34038
- normalizeLeaseMs(requestedLeaseMs) {
34039
- const defaultLeaseMs = this.options.defaultLeaseMs ?? 30000;
34040
- const maxLeaseMs = this.options.maxLeaseMs ?? 300000;
34041
- if (!requestedLeaseMs || !Number.isFinite(requestedLeaseMs) || requestedLeaseMs <= 0) {
34042
- return defaultLeaseMs;
34043
- }
34044
- return Math.min(Math.max(requestedLeaseMs, 5000), maxLeaseMs);
34045
- }
34046
- requireConversationAuthority(conversationId) {
34047
- const conversation = this.options.runtime.conversation(conversationId);
34048
- if (!conversation) {
34049
- throw new ThreadWatchProtocolError(404, {
34050
- code: "unknown_conversation",
34051
- message: `unknown conversation ${conversationId}`
34052
- });
34053
- }
34054
- if (conversation.authorityNodeId !== this.options.nodeId) {
34055
- throw new ThreadWatchProtocolError(409, {
34056
- code: "no_responder",
34057
- message: `conversation ${conversationId} is owned by ${conversation.authorityNodeId}`
34058
- });
34059
- }
34060
- return conversation;
34061
- }
34062
- requireRemoteWatchAllowed(conversation) {
34063
- if (conversation.shareMode === "local") {
34064
- throw new ThreadWatchProtocolError(403, {
34065
- code: "forbidden",
34066
- message: `conversation ${conversation.id} does not allow remote watches`
34067
- });
34068
- }
34069
- }
34070
- requireLiveWatch(watchId) {
34071
- const watch = this.watches.get(watchId);
34072
- if (!watch) {
34073
- throw new ThreadWatchProtocolError(404, {
34074
- code: "invalid_request",
34075
- message: `unknown watch ${watchId}`
34076
- });
34077
- }
34078
- if (watch.leaseExpiresAt <= Date.now()) {
34079
- this.closeWatchInternal(watchId);
34080
- throw new ThreadWatchProtocolError(410, {
34081
- code: "lease_expired",
34082
- message: `watch ${watchId} lease expired`
34083
- });
34084
- }
34085
- return watch;
34086
- }
34087
- indexWatch(watch) {
34088
- const ids = this.watchIdsByConversation.get(watch.conversationId) ?? new Set;
34089
- ids.add(watch.watchId);
34090
- this.watchIdsByConversation.set(watch.conversationId, ids);
34091
- }
34092
- closeWatchInternal(watchId) {
34093
- const watch = this.watches.get(watchId);
34094
- if (!watch) {
34095
- return;
34096
- }
34097
- this.watches.delete(watchId);
34098
- this.watchIdsByKey.delete(watchKey(watch.conversationId, watch.watcherNodeId, watch.watcherId));
34099
- const ids = this.watchIdsByConversation.get(watch.conversationId);
34100
- if (ids) {
34101
- ids.delete(watchId);
34102
- if (ids.size === 0) {
34103
- this.watchIdsByConversation.delete(watch.conversationId);
34104
- }
34105
- }
34106
- for (const client of watch.clients) {
34107
- client.end();
34108
- }
34109
- watch.clients.clear();
34110
- }
34111
- }
34112
32122
  // ../runtime/src/mobile-push.ts
34113
32123
  import { Database as Database2 } from "bun:sqlite";
34114
32124
  import { mkdirSync as mkdirSync9, readFileSync as readFileSync10 } from "fs";
34115
32125
  import { connect as connectHttp2 } from "http2";
34116
32126
  import { createPrivateKey, sign as signWithKey } from "crypto";
34117
- import { dirname as dirname7, join as join18 } from "path";
32127
+ import { dirname as dirname8, join as join19 } from "path";
34118
32128
  var MOBILE_PUSH_SCHEMA = `
34119
32129
  CREATE TABLE IF NOT EXISTS mobile_push_registrations (
34120
32130
  id TEXT PRIMARY KEY,
@@ -34142,7 +32152,7 @@ var dbHandle = null;
34142
32152
  var dbPath = null;
34143
32153
  var cachedApnsJwt = null;
34144
32154
  function resolveControlPlaneDbPath() {
34145
- return join18(resolveOpenScoutSupportPaths().controlHome, "control-plane.sqlite");
32155
+ return join19(resolveOpenScoutSupportPaths().controlHome, "control-plane.sqlite");
34146
32156
  }
34147
32157
  function ensureMobilePushSchema(database) {
34148
32158
  database.exec("PRAGMA busy_timeout = 5000;");
@@ -34156,7 +32166,7 @@ function writeDb() {
34156
32166
  dbHandle = null;
34157
32167
  }
34158
32168
  if (!dbHandle) {
34159
- mkdirSync9(dirname7(nextPath), { recursive: true });
32169
+ mkdirSync9(dirname8(nextPath), { recursive: true });
34160
32170
  dbHandle = new Database2(nextPath, { create: true });
34161
32171
  dbPath = nextPath;
34162
32172
  ensureMobilePushSchema(dbHandle);
@@ -34372,7 +32382,7 @@ async function sendApnsAlertToRegistration(registration, alert) {
34372
32382
  },
34373
32383
  ...alert.payload ? { scout: alert.payload } : {}
34374
32384
  });
34375
- return new Promise((resolve7, reject) => {
32385
+ return new Promise((resolve8, reject) => {
34376
32386
  const client = connectHttp2(authority);
34377
32387
  client.once("error", reject);
34378
32388
  const request = client.request({
@@ -34410,7 +32420,7 @@ async function sendApnsAlertToRegistration(registration, alert) {
34410
32420
  }
34411
32421
  }
34412
32422
  if (status === 200) {
34413
- resolve7({
32423
+ resolve8({
34414
32424
  delivered: true,
34415
32425
  skipped: false,
34416
32426
  status,
@@ -34422,7 +32432,7 @@ async function sendApnsAlertToRegistration(registration, alert) {
34422
32432
  if (reason === "BadDeviceToken" || reason === "Unregistered") {
34423
32433
  deleteMobilePushRegistrationByToken(registration.pushToken);
34424
32434
  }
34425
- resolve7({
32435
+ resolve8({
34426
32436
  delivered: false,
34427
32437
  skipped: false,
34428
32438
  status,
@@ -34481,11 +32491,12 @@ async function broadcastApnsAlertToActiveMobileDevices(alert) {
34481
32491
  failures
34482
32492
  };
34483
32493
  }
32494
+
34484
32495
  // ../../apps/desktop/src/core/pairing/runtime/bridge/router.ts
34485
32496
  import { readFileSync as readFileSync11, readdirSync as readdirSync4, realpathSync as realpathSync2, statSync as statSync4 } from "fs";
34486
32497
  import { execSync as execSync4 } from "child_process";
34487
- import { basename as basename7, isAbsolute as isAbsolute4, join as join19, relative as relative3 } from "path";
34488
- import { homedir as homedir16 } from "os";
32498
+ import { basename as basename8, isAbsolute as isAbsolute4, join as join20, relative as relative3 } from "path";
32499
+ import { homedir as homedir17 } from "os";
34489
32500
  var t = initTRPC.context().create();
34490
32501
  var logged = t.middleware(async ({ path: path2, type, next }) => {
34491
32502
  const start = Date.now();
@@ -34512,13 +32523,13 @@ function resolveMobileCurrentDirectory2() {
34512
32523
  }
34513
32524
  }
34514
32525
  function resolveWorkspaceRoot2(root) {
34515
- const expandedRoot = root.replace(/^~/, homedir16());
32526
+ const expandedRoot = root.replace(/^~/, homedir17());
34516
32527
  return realpathSync2(expandedRoot);
34517
32528
  }
34518
32529
  function resolveWorkspacePath2(root, requestedPath) {
34519
32530
  const normalizedRoot = resolveWorkspaceRoot2(root);
34520
- const expandedPath = requestedPath?.replace(/^~/, homedir16());
34521
- const candidate = expandedPath ? isAbsolute4(expandedPath) ? expandedPath : join19(normalizedRoot, expandedPath) : normalizedRoot;
32531
+ const expandedPath = requestedPath?.replace(/^~/, homedir17());
32532
+ const candidate = expandedPath ? isAbsolute4(expandedPath) ? expandedPath : join20(normalizedRoot, expandedPath) : normalizedRoot;
34522
32533
  const resolvedCandidate = realpathSync2(candidate);
34523
32534
  const rel = relative3(normalizedRoot, resolvedCandidate);
34524
32535
  if (rel === "" || !rel.startsWith("..") && !isAbsolute4(rel)) {
@@ -34548,7 +32559,7 @@ function listDirectories2(dirPath) {
34548
32559
  continue;
34549
32560
  if (name === "node_modules" || name === ".build" || name === "target")
34550
32561
  continue;
34551
- const fullPath = join19(dirPath, name);
32562
+ const fullPath = join20(dirPath, name);
34552
32563
  try {
34553
32564
  const stat4 = statSync4(fullPath);
34554
32565
  if (!stat4.isDirectory())
@@ -34587,7 +32598,7 @@ function detectAgent2(filePath) {
34587
32598
  return "unknown";
34588
32599
  }
34589
32600
  async function discoverSessionFiles2(maxAgeDays, limit) {
34590
- const home = homedir16();
32601
+ const home = homedir17();
34591
32602
  const results = [];
34592
32603
  const searchPaths = [
34593
32604
  { pattern: `${home}/.claude/projects`, agent: "claude-code" },
@@ -34669,23 +32680,23 @@ function bridgeEventIterable(bridge, signal) {
34669
32680
  return {
34670
32681
  [Symbol.asyncIterator]() {
34671
32682
  const buffer = [];
34672
- let resolve7 = null;
32683
+ let resolve8 = null;
34673
32684
  let done = false;
34674
32685
  const unsub = bridge.onEvent((event) => {
34675
32686
  if (done)
34676
32687
  return;
34677
32688
  buffer.push(event);
34678
- if (resolve7) {
34679
- resolve7();
34680
- resolve7 = null;
32689
+ if (resolve8) {
32690
+ resolve8();
32691
+ resolve8 = null;
34681
32692
  }
34682
32693
  });
34683
32694
  const cleanup = () => {
34684
32695
  done = true;
34685
32696
  unsub();
34686
- if (resolve7) {
34687
- resolve7();
34688
- resolve7 = null;
32697
+ if (resolve8) {
32698
+ resolve8();
32699
+ resolve8 = null;
34689
32700
  }
34690
32701
  };
34691
32702
  signal?.addEventListener("abort", cleanup, { once: true });
@@ -34698,7 +32709,7 @@ function bridgeEventIterable(bridge, signal) {
34698
32709
  return { done: false, value: buffer.shift() };
34699
32710
  }
34700
32711
  await new Promise((r) => {
34701
- resolve7 = r;
32712
+ resolve8 = r;
34702
32713
  });
34703
32714
  }
34704
32715
  },
@@ -34717,8 +32728,8 @@ function getEventSessionId(event) {
34717
32728
  function trackedSequencedEventId(event) {
34718
32729
  return `${getEventSessionId(event) ?? "unknown"}:${event.seq}`;
34719
32730
  }
34720
- function approvalInboxItemId(sessionId, turnId, blockId, version3) {
34721
- return `approval:${sessionId}:${turnId}:${blockId}:v${version3}`;
32731
+ function approvalInboxItemId(sessionId, turnId, blockId, version2) {
32732
+ return `approval:${sessionId}:${turnId}:${blockId}:v${version2}`;
34722
32733
  }
34723
32734
  function projectApprovalInboxItem(snapshot, turn, block) {
34724
32735
  const normalized = normalizeApprovalRequest(snapshot.session, turn.id, block);
@@ -34827,9 +32838,9 @@ var sessionRouter = t.router({
34827
32838
  adapterType: exports_external.string().optional(),
34828
32839
  name: exports_external.string().optional()
34829
32840
  })).mutation(async ({ input, ctx }) => {
34830
- const sessionFilename = basename7(input.sessionPath, ".jsonl");
32841
+ const sessionFilename = basename8(input.sessionPath, ".jsonl");
34831
32842
  const parentDir = input.sessionPath.substring(0, input.sessionPath.lastIndexOf("/"));
34832
- const dirName = basename7(parentDir);
32843
+ const dirName = basename8(parentDir);
34833
32844
  let cwd;
34834
32845
  if (dirName.startsWith("-")) {
34835
32846
  const candidate = "/" + dirName.slice(1).replace(/-/g, "/");
@@ -35129,7 +33140,7 @@ var workspaceRouter = t.router({
35129
33140
  });
35130
33141
  }
35131
33142
  const adapterType = input.adapter ?? "claude-code";
35132
- const name = input.name ?? basename7(projectPath);
33143
+ const name = input.name ?? basename8(projectPath);
35133
33144
  return ctx.bridge.createSession(adapterType, {
35134
33145
  name,
35135
33146
  cwd: projectPath
@@ -35376,7 +33387,8 @@ var BACKOFF_MULTIPLIER = 2;
35376
33387
  var LEGACY_CLIENT_ID = "__legacy__";
35377
33388
  function connectToRelay(relayUrl, identity2, bridge, options = {}) {
35378
33389
  const { secure = true, events: events2 } = options;
35379
- const qrPayload = createQRPayload(identity2.publicKey, relayUrl);
33390
+ const publicRelayUrl = options.publicRelayUrl?.trim() || relayUrl;
33391
+ const qrPayload = createQRPayload(identity2.publicKey, publicRelayUrl, options.fallbackRelayUrls);
35380
33392
  let ws = null;
35381
33393
  let eventUnsub = null;
35382
33394
  let stopped = false;
@@ -35390,12 +33402,12 @@ function connectToRelay(relayUrl, identity2, bridge, options = {}) {
35390
33402
  const bridgeKeyHex = bytesToHex2(identity2.publicKey);
35391
33403
  const url2 = buildRelayUrl(relayUrl, qrPayload.room, bridgeKeyHex);
35392
33404
  console.log(`[relay-client] connecting to relay (room: ${qrPayload.room})`);
35393
- events2?.onConnecting?.({ relayUrl, room: qrPayload.room });
33405
+ events2?.onConnecting?.({ relayUrl: publicRelayUrl, room: qrPayload.room });
35394
33406
  ws = new WebSocket(url2, relayWebSocketOptions(relayUrl));
35395
33407
  ws.addEventListener("open", () => {
35396
33408
  console.log(`[relay-client] connected to relay (room: ${qrPayload.room})`);
35397
33409
  backoff = INITIAL_BACKOFF_MS;
35398
- events2?.onConnected?.({ relayUrl, room: qrPayload.room });
33410
+ events2?.onConnected?.({ relayUrl: publicRelayUrl, room: qrPayload.room });
35399
33411
  });
35400
33412
  ws.addEventListener("message", (event) => {
35401
33413
  handleRelaySocketMessage(event.data);
@@ -35403,7 +33415,7 @@ function connectToRelay(relayUrl, identity2, bridge, options = {}) {
35403
33415
  ws.addEventListener("close", (event) => {
35404
33416
  console.log(`[relay-client] disconnected (code: ${event.code}, reason: ${event.reason})`);
35405
33417
  events2?.onClosed?.({
35406
- relayUrl,
33418
+ relayUrl: publicRelayUrl,
35407
33419
  room: qrPayload.room,
35408
33420
  code: event.code,
35409
33421
  reason: event.reason
@@ -35414,7 +33426,7 @@ function connectToRelay(relayUrl, identity2, bridge, options = {}) {
35414
33426
  ws.addEventListener("error", () => {
35415
33427
  const error48 = new Error("Relay websocket error");
35416
33428
  console.error("[relay-client] connection error");
35417
- events2?.onError?.({ relayUrl, room: qrPayload.room, error: error48 });
33429
+ events2?.onError?.({ relayUrl: publicRelayUrl, room: qrPayload.room, error: error48 });
35418
33430
  });
35419
33431
  }
35420
33432
  function handleRelaySocketMessage(raw) {
@@ -35468,7 +33480,7 @@ function connectToRelay(relayUrl, identity2, bridge, options = {}) {
35468
33480
  replaceOlderPeerForSameDevice(peer);
35469
33481
  ensureBridgeEventSubscription();
35470
33482
  console.log(`[relay-client] secure handshake complete (peer: ${pubHex.slice(0, 12)}..., device: ${peer.deviceId}, client: ${clientId})`);
35471
- events2?.onPaired?.({ relayUrl, room: qrPayload.room, remotePublicKey });
33483
+ events2?.onPaired?.({ relayUrl: publicRelayUrl, room: qrPayload.room, remotePublicKey });
35472
33484
  sendExistingSessions((json2) => {
35473
33485
  if (peer.transport.isReady()) {
35474
33486
  peer.transport.send(json2);
@@ -35481,7 +33493,7 @@ function connectToRelay(relayUrl, identity2, bridge, options = {}) {
35481
33493
  onError: (err) => {
35482
33494
  console.error("[relay-client] secure transport error:", err.message);
35483
33495
  log.error("trns:cry", `decrypt failed for ${clientId} \u2014 resetting handshake: ${err.message}`);
35484
- events2?.onError?.({ relayUrl, room: qrPayload.room, error: err });
33496
+ events2?.onError?.({ relayUrl: publicRelayUrl, room: qrPayload.room, error: err });
35485
33497
  sendRelayClose(clientId, 4002, "Transport reset");
35486
33498
  teardownSecurePeer(clientId);
35487
33499
  },
@@ -35680,7 +33692,7 @@ function connectToRelay(relayUrl, identity2, bridge, options = {}) {
35680
33692
  if (stopped)
35681
33693
  return;
35682
33694
  console.log(`[relay-client] reconnecting in ${backoff}ms...`);
35683
- events2?.onReconnectScheduled?.({ relayUrl, room: qrPayload.room, delayMs: backoff });
33695
+ events2?.onReconnectScheduled?.({ relayUrl: publicRelayUrl, room: qrPayload.room, delayMs: backoff });
35684
33696
  reconnectTimer = setTimeout(() => {
35685
33697
  reconnectTimer = null;
35686
33698
  connect();
@@ -35772,13 +33784,13 @@ function asStringPayload(raw) {
35772
33784
  // ../../node_modules/.bun/hono@4.12.10/node_modules/hono/dist/compose.js
35773
33785
  var compose = (middleware, onError, onNotFound) => {
35774
33786
  return (context, next) => {
35775
- let index2 = -1;
33787
+ let index = -1;
35776
33788
  return dispatch(0);
35777
33789
  async function dispatch(i) {
35778
- if (i <= index2) {
33790
+ if (i <= index) {
35779
33791
  throw new Error("next() called multiple times");
35780
33792
  }
35781
- index2 = i;
33793
+ index = i;
35782
33794
  let res;
35783
33795
  let isError = false;
35784
33796
  let handler;
@@ -35875,8 +33887,8 @@ var handleParsingNestedValues = (form, key, value) => {
35875
33887
  }
35876
33888
  let nestedForm = form;
35877
33889
  const keys = key.split(".");
35878
- keys.forEach((key2, index2) => {
35879
- if (index2 === keys.length - 1) {
33890
+ keys.forEach((key2, index) => {
33891
+ if (index === keys.length - 1) {
35880
33892
  nestedForm[key2] = value;
35881
33893
  } else {
35882
33894
  if (!nestedForm[key2] || typeof nestedForm[key2] !== "object" || Array.isArray(nestedForm[key2]) || nestedForm[key2] instanceof File) {
@@ -35902,8 +33914,8 @@ var splitRoutingPath = (routePath) => {
35902
33914
  };
35903
33915
  var extractGroupsFromPath = (path2) => {
35904
33916
  const groups = [];
35905
- path2 = path2.replace(/\{[^}]+\}/g, (match, index2) => {
35906
- const mark = `@${index2}`;
33917
+ path2 = path2.replace(/\{[^}]+\}/g, (match, index) => {
33918
+ const mark = `@${index}`;
35907
33919
  groups.push([mark, match]);
35908
33920
  return mark;
35909
33921
  });
@@ -36161,7 +34173,7 @@ var HonoRequest = class {
36161
34173
  return bodyCache[key] = raw[key]();
36162
34174
  };
36163
34175
  json() {
36164
- return this.#cachedBody("text").then((text2) => JSON.parse(text2));
34176
+ return this.#cachedBody("text").then((text) => JSON.parse(text));
36165
34177
  }
36166
34178
  text() {
36167
34179
  return this.#cachedBody("text");
@@ -36382,8 +34394,8 @@ var Context = class {
36382
34394
  }
36383
34395
  newResponse = (...args) => this.#newResponse(...args);
36384
34396
  body = (data, arg, headers) => this.#newResponse(data, arg, headers);
36385
- text = (text2, arg, headers) => {
36386
- return !this.#preparedHeaders && !this.#status && !arg && !headers && !this.finalized ? new Response(text2) : this.#newResponse(text2, arg, setDefaultContentType(TEXT_PLAIN, headers));
34397
+ text = (text, arg, headers) => {
34398
+ return !this.#preparedHeaders && !this.#status && !arg && !headers && !this.finalized ? new Response(text) : this.#newResponse(text, arg, setDefaultContentType(TEXT_PLAIN, headers));
36387
34399
  };
36388
34400
  json = (object2, arg, headers) => {
36389
34401
  return this.#newResponse(JSON.stringify(object2), arg, setDefaultContentType("application/json", headers));
@@ -36647,8 +34659,8 @@ function match(method, path2) {
36647
34659
  if (!match3) {
36648
34660
  return [[], emptyParam];
36649
34661
  }
36650
- const index2 = match3.indexOf("", 1);
36651
- return [matcher[1][index2], match3];
34662
+ const index = match3.indexOf("", 1);
34663
+ return [matcher[1][index], match3];
36652
34664
  };
36653
34665
  this.match = match2;
36654
34666
  return match2(method, path2);
@@ -36683,7 +34695,7 @@ var Node = class _Node {
36683
34695
  #index;
36684
34696
  #varIndex;
36685
34697
  #children = /* @__PURE__ */ Object.create(null);
36686
- insert(tokens, index2, paramMap, context, pathErrorCheckOnly) {
34698
+ insert(tokens, index, paramMap, context, pathErrorCheckOnly) {
36687
34699
  if (tokens.length === 0) {
36688
34700
  if (this.#index !== undefined) {
36689
34701
  throw PATH_ERROR;
@@ -36691,7 +34703,7 @@ var Node = class _Node {
36691
34703
  if (pathErrorCheckOnly) {
36692
34704
  return;
36693
34705
  }
36694
- this.#index = index2;
34706
+ this.#index = index;
36695
34707
  return;
36696
34708
  }
36697
34709
  const [token, ...restTokens] = tokens;
@@ -36737,7 +34749,7 @@ var Node = class _Node {
36737
34749
  node = this.#children[token] = new _Node;
36738
34750
  }
36739
34751
  }
36740
- node.insert(restTokens, index2, paramMap, context, pathErrorCheckOnly);
34752
+ node.insert(restTokens, index, paramMap, context, pathErrorCheckOnly);
36741
34753
  }
36742
34754
  buildRegExpStr() {
36743
34755
  const childKeys = Object.keys(this.#children).sort(compareKey);
@@ -36762,7 +34774,7 @@ var Node = class _Node {
36762
34774
  var Trie = class {
36763
34775
  #context = { varIndex: 0 };
36764
34776
  #root = new Node;
36765
- insert(path2, index2, pathErrorCheckOnly) {
34777
+ insert(path2, index, pathErrorCheckOnly) {
36766
34778
  const paramAssoc = [];
36767
34779
  const groups = [];
36768
34780
  for (let i = 0;; ) {
@@ -36788,7 +34800,7 @@ var Trie = class {
36788
34800
  }
36789
34801
  }
36790
34802
  }
36791
- this.#root.insert(tokens, index2, paramAssoc, this.#context, pathErrorCheckOnly);
34803
+ this.#root.insert(tokens, index, paramAssoc, this.#context, pathErrorCheckOnly);
36792
34804
  return paramAssoc;
36793
34805
  }
36794
34806
  buildRegExp() {
@@ -36998,11 +35010,11 @@ var PreparedRegExpRouter = class {
36998
35010
  if (!map2) {
36999
35011
  matcher[2][path2][0].push([handler, {}]);
37000
35012
  } else {
37001
- indexes.forEach((index2) => {
37002
- if (typeof index2 === "number") {
37003
- matcher[1][index2].push([handler, map2]);
35013
+ indexes.forEach((index) => {
35014
+ if (typeof index === "number") {
35015
+ matcher[1][index].push([handler, map2]);
37004
35016
  } else {
37005
- matcher[2][index2 || path2][0].push([handler, map2]);
35017
+ matcher[2][index || path2][0].push([handler, map2]);
37006
35018
  }
37007
35019
  });
37008
35020
  }
@@ -37481,22 +35493,22 @@ var jsonContentTypeHandler = {
37481
35493
  message: '"input" needs to be an object when doing a batch call'
37482
35494
  });
37483
35495
  const acc = emptyObject();
37484
- for (const index2 of paths.keys()) {
37485
- const input = inputs[index2];
35496
+ for (const index of paths.keys()) {
35497
+ const input = inputs[index];
37486
35498
  if (input !== undefined)
37487
- acc[index2] = opts.router._def._config.transformer.input.deserialize(input);
35499
+ acc[index] = opts.router._def._config.transformer.input.deserialize(input);
37488
35500
  }
37489
35501
  return acc;
37490
35502
  });
37491
- const calls = await Promise.all(paths.map(async (path2, index2) => {
35503
+ const calls = await Promise.all(paths.map(async (path2, index) => {
37492
35504
  const procedure2 = await getProcedureAtPath(opts.router, path2);
37493
35505
  return {
37494
- batchIndex: index2,
35506
+ batchIndex: index,
37495
35507
  path: path2,
37496
35508
  procedure: procedure2,
37497
35509
  getRawInput: async () => {
37498
35510
  const inputs = await getInputs.read();
37499
- let input = inputs[index2];
35511
+ let input = inputs[index];
37500
35512
  if ((procedure2 === null || procedure2 === undefined ? undefined : procedure2._def.type) === "subscription") {
37501
35513
  var _ref2, _opts$headers$get;
37502
35514
  const lastEventId = (_ref2 = (_opts$headers$get = opts.headers.get("last-event-id")) !== null && _opts$headers$get !== undefined ? _opts$headers$get : opts.searchParams.get("lastEventId")) !== null && _ref2 !== undefined ? _ref2 : opts.searchParams.get("Last-Event-Id");
@@ -37512,7 +35524,7 @@ var jsonContentTypeHandler = {
37512
35524
  },
37513
35525
  result: () => {
37514
35526
  var _getInputs$result;
37515
- return (_getInputs$result = getInputs.result()) === null || _getInputs$result === undefined ? undefined : _getInputs$result[index2];
35527
+ return (_getInputs$result = getInputs.result()) === null || _getInputs$result === undefined ? undefined : _getInputs$result[index];
37516
35528
  }
37517
35529
  };
37518
35530
  }));
@@ -37676,8 +35688,8 @@ var Unpromise = class Unpromise2 {
37676
35688
  status: "fulfilled",
37677
35689
  value
37678
35690
  };
37679
- subscribers === null || subscribers === undefined || subscribers.forEach(({ resolve: resolve7 }) => {
37680
- resolve7(value);
35691
+ subscribers === null || subscribers === undefined || subscribers.forEach(({ resolve: resolve8 }) => {
35692
+ resolve8(value);
37681
35693
  });
37682
35694
  });
37683
35695
  if ("catch" in thenReturn)
@@ -37785,28 +35797,28 @@ function resolveSelfTuple(promise2) {
37785
35797
  return Unpromise.proxy(promise2).then(() => [promise2]);
37786
35798
  }
37787
35799
  function withResolvers() {
37788
- let resolve7;
35800
+ let resolve8;
37789
35801
  let reject;
37790
35802
  const promise2 = new Promise((_resolve, _reject) => {
37791
- resolve7 = _resolve;
35803
+ resolve8 = _resolve;
37792
35804
  reject = _reject;
37793
35805
  });
37794
35806
  return {
37795
35807
  promise: promise2,
37796
- resolve: resolve7,
35808
+ resolve: resolve8,
37797
35809
  reject
37798
35810
  };
37799
35811
  }
37800
35812
  function listWithMember(arr, member) {
37801
35813
  return [...arr, member];
37802
35814
  }
37803
- function listWithoutIndex(arr, index2) {
37804
- return [...arr.slice(0, index2), ...arr.slice(index2 + 1)];
35815
+ function listWithoutIndex(arr, index) {
35816
+ return [...arr.slice(0, index), ...arr.slice(index + 1)];
37805
35817
  }
37806
35818
  function listWithoutMember(arr, member) {
37807
- const index2 = arr.indexOf(member);
37808
- if (index2 !== -1)
37809
- return listWithoutIndex(arr, index2);
35819
+ const index = arr.indexOf(member);
35820
+ if (index !== -1)
35821
+ return listWithoutIndex(arr, index);
37810
35822
  return arr;
37811
35823
  }
37812
35824
  var _Symbol;
@@ -37839,8 +35851,8 @@ function timerResource(ms) {
37839
35851
  return makeResource({ start() {
37840
35852
  if (timer)
37841
35853
  throw new Error("Timer already started");
37842
- const promise2 = new Promise((resolve7) => {
37843
- timer = setTimeout(() => resolve7(disposablePromiseTimerResult), ms);
35854
+ const promise2 = new Promise((resolve8) => {
35855
+ timer = setTimeout(() => resolve8(disposablePromiseTimerResult), ms);
37844
35856
  });
37845
35857
  return promise2;
37846
35858
  } }, () => {
@@ -38043,15 +36055,15 @@ function _takeWithGrace() {
38043
36055
  return _takeWithGrace.apply(this, arguments);
38044
36056
  }
38045
36057
  function createDeferred() {
38046
- let resolve7;
36058
+ let resolve8;
38047
36059
  let reject;
38048
36060
  const promise2 = new Promise((res, rej) => {
38049
- resolve7 = res;
36061
+ resolve8 = res;
38050
36062
  reject = rej;
38051
36063
  });
38052
36064
  return {
38053
36065
  promise: promise2,
38054
- resolve: resolve7,
36066
+ resolve: resolve8,
38055
36067
  reject
38056
36068
  };
38057
36069
  }
@@ -39019,9 +37031,9 @@ async function resolveResponse(opts) {
39019
37031
  });
39020
37032
  const stream = jsonlStreamProducer((0, import_objectSpread24.default)((0, import_objectSpread24.default)({}, config2.jsonl), {}, {
39021
37033
  maxDepth: Infinity,
39022
- data: rpcCalls.map(async (res, index2) => {
37034
+ data: rpcCalls.map(async (res, index) => {
39023
37035
  const [error48, result] = await res;
39024
- const call = info.calls[index2];
37036
+ const call = info.calls[index];
39025
37037
  if (error48) {
39026
37038
  var _procedure$_def$type, _procedure;
39027
37039
  return { error: getErrorShape({
@@ -39083,8 +37095,8 @@ async function resolveResponse(opts) {
39083
37095
  }), undefined];
39084
37096
  return res;
39085
37097
  });
39086
- const resultAsRPCResponse = results.map(([error48, result], index2) => {
39087
- const call = info.calls[index2];
37098
+ const resultAsRPCResponse = results.map(([error48, result], index) => {
37099
+ const call = info.calls[index];
39088
37100
  if (error48) {
39089
37101
  var _call$procedure$_def$4, _call$procedure5;
39090
37102
  return { error: getErrorShape({
@@ -39189,7 +37201,7 @@ async function fetchRequestHandler(opts) {
39189
37201
 
39190
37202
  // ../../node_modules/.bun/hono@4.12.10/node_modules/hono/dist/helper/route/index.js
39191
37203
  var matchedRoutes = (c) => c.req[GET_MATCH_RESULT][0].map(([[, route2]]) => route2);
39192
- var routePath = (c, index2) => matchedRoutes(c).at(index2 ?? c.req.routeIndex)?.path ?? "";
37204
+ var routePath = (c, index) => matchedRoutes(c).at(index ?? c.req.routeIndex)?.path ?? "";
39193
37205
 
39194
37206
  // ../../node_modules/.bun/@hono+trpc-server@0.4.2+2b2485a92adeb0d0/node_modules/@hono/trpc-server/dist/index.js
39195
37207
  var trpcServer = ({ endpoint, createContext, ...rest }) => {
@@ -39282,14 +37294,14 @@ function parseTRPCMessage(obj, transformer) {
39282
37294
  }
39283
37295
  // ../../apps/desktop/src/core/pairing/runtime/bridge/server-trpc.ts
39284
37296
  import { realpathSync as realpathSync3 } from "fs";
39285
- import { homedir as homedir17 } from "os";
37297
+ import { homedir as homedir18 } from "os";
39286
37298
  function resolveCurrentDirectory() {
39287
37299
  try {
39288
37300
  const config2 = resolveConfig();
39289
37301
  const configuredRoot = config2.workspace?.root;
39290
37302
  if (!configuredRoot)
39291
37303
  return process.cwd();
39292
- const expanded = configuredRoot.replace(/^~/, homedir17());
37304
+ const expanded = configuredRoot.replace(/^~/, homedir18());
39293
37305
  return realpathSync3(expanded);
39294
37306
  } catch {
39295
37307
  return process.cwd();
@@ -39352,14 +37364,14 @@ function startBridgeServerTRPC(options) {
39352
37364
  }
39353
37365
  };
39354
37366
  }
39355
- async function handleTRPCMessage(ws, state, text2) {
37367
+ async function handleTRPCMessage(ws, state, text) {
39356
37368
  const send = createSender(ws, state);
39357
37369
  if (!bridgeRouter) {
39358
- await handleLegacyFallback(ws, state, text2);
37370
+ await handleLegacyFallback(ws, state, text);
39359
37371
  return;
39360
37372
  }
39361
37373
  try {
39362
- const msgJSON = JSON.parse(text2);
37374
+ const msgJSON = JSON.parse(text);
39363
37375
  const msgs = Array.isArray(msgJSON) ? msgJSON : [msgJSON];
39364
37376
  for (const raw2 of msgs) {
39365
37377
  log.info("rpc:req", `\u2192 ${raw2.params?.path ?? raw2.method ?? "?"}`);
@@ -39436,8 +37448,8 @@ function startBridgeServerTRPC(options) {
39436
37448
  }
39437
37449
  const iterable = isObservable(result) ? observableToAsyncIterable(result, abortController.signal) : result;
39438
37450
  const iterator = iterable[Symbol.asyncIterator]();
39439
- const abortPromise = new Promise((resolve7) => {
39440
- abortController.signal.addEventListener("abort", () => resolve7("abort"), {
37451
+ const abortPromise = new Promise((resolve8) => {
37452
+ abortController.signal.addEventListener("abort", () => resolve8("abort"), {
39441
37453
  once: true
39442
37454
  });
39443
37455
  });
@@ -39548,7 +37560,7 @@ function startBridgeServerTRPC(options) {
39548
37560
  });
39549
37561
  }
39550
37562
  }
39551
- async function handleLegacyFallback(ws, state, text2) {
37563
+ async function handleLegacyFallback(ws, state, text) {
39552
37564
  const sendRaw = (json2) => {
39553
37565
  if (state.transport) {
39554
37566
  state.transport.send(json2);
@@ -39558,7 +37570,7 @@ function startBridgeServerTRPC(options) {
39558
37570
  };
39559
37571
  let req;
39560
37572
  try {
39561
- req = JSON.parse(text2);
37573
+ req = JSON.parse(text);
39562
37574
  } catch {
39563
37575
  sendRaw(JSON.stringify({ id: null, error: { code: -32700, message: "Parse error" } }));
39564
37576
  return;
@@ -39672,8 +37684,8 @@ function startBridgeServerTRPC(options) {
39672
37684
  const data = typeof raw2 === "string" ? raw2 : new Uint8Array(raw2);
39673
37685
  state.transport.receive(data);
39674
37686
  } else {
39675
- const text2 = typeof raw2 === "string" ? raw2 : new TextDecoder().decode(raw2);
39676
- handleTRPCMessage(ws, state, text2);
37687
+ const text = typeof raw2 === "string" ? raw2 : new TextDecoder().decode(raw2);
37688
+ handleTRPCMessage(ws, state, text);
39677
37689
  }
39678
37690
  },
39679
37691
  close(ws) {
@@ -39782,6 +37794,8 @@ async function startPairingRuntime(options) {
39782
37794
  }
39783
37795
  const relayConnection = connectToRelay(relayUrl, identity2, bridge, {
39784
37796
  secure: true,
37797
+ publicRelayUrl: options?.advertisedRelayUrl ?? undefined,
37798
+ fallbackRelayUrls: options?.fallbackRelayUrls,
39785
37799
  events: options?.relayEvents
39786
37800
  });
39787
37801
  await autoStartConfiguredSessions(bridge, config2.sessions);
@@ -39809,7 +37823,7 @@ async function autoStartConfiguredSessions(bridge, sessions3) {
39809
37823
  try {
39810
37824
  const session = await bridge.createSession(entry.adapter, {
39811
37825
  name: entry.name,
39812
- cwd: entry.cwd?.replace(/^~/, homedir18()),
37826
+ cwd: entry.cwd?.replace(/^~/, homedir19()),
39813
37827
  options: entry.options
39814
37828
  });
39815
37829
  console.log(`[bridge] session started: ${session.name} (${entry.adapter})`);
@@ -39823,6 +37837,7 @@ async function autoStartConfiguredSessions(bridge, sessions3) {
39823
37837
  // ../../apps/desktop/src/core/pairing/supervisor.ts
39824
37838
  var SCOUT_PAIR_REFRESH_LEEWAY_MS = 30000;
39825
37839
  var SCOUT_PAIR_RESTART_DELAY_MS = 2000;
37840
+ var BONJOUR_SERVICE_TYPE = "_scout-pair._tcp";
39826
37841
  async function runScoutPairingSupervisor() {
39827
37842
  clearStalePairingRuntimeFiles();
39828
37843
  const existingPid = readPairingRuntimePid();
@@ -39844,7 +37859,8 @@ async function runScoutPairingSupervisor() {
39844
37859
  refreshTimer: null,
39845
37860
  intentionalStop: false,
39846
37861
  runtime: null,
39847
- relay: null
37862
+ relay: null,
37863
+ bonjour: null
39848
37864
  };
39849
37865
  const shutdown = async () => {
39850
37866
  state.intentionalStop = true;
@@ -39872,6 +37888,8 @@ async function startSupervisorRuntime(state) {
39872
37888
  const config2 = resolvedPairingConfig();
39873
37889
  const relayPort = config2.port + 1;
39874
37890
  const resolvedRelayUrl = config2.relay?.trim() || null;
37891
+ const identity2 = loadOrCreateIdentity();
37892
+ const publicKeyHex = bytesToHex2(identity2.publicKey);
39875
37893
  writeCurrent(state, {
39876
37894
  status: "starting",
39877
37895
  statusLabel: "Starting",
@@ -39883,12 +37901,24 @@ async function startSupervisorRuntime(state) {
39883
37901
  });
39884
37902
  const emitStatus = createStatusWriter(state);
39885
37903
  try {
39886
- const activeRelayUrl = resolvedRelayUrl ?? (() => {
37904
+ const managedRelay = resolvedRelayUrl ? null : (() => {
39887
37905
  state.relay = startManagedRelay(relayPort);
39888
- return state.relay.relayUrl;
37906
+ return state.relay;
39889
37907
  })();
39890
- state.runtime = await startPairingRuntime({
37908
+ const activeRelayUrl = resolvedRelayUrl ?? managedRelay?.relayUrl;
37909
+ const connectRelayUrl = resolvedRelayUrl ?? managedRelay?.connectUrl ?? managedRelay?.relayUrl;
37910
+ if (!activeRelayUrl || !connectRelayUrl) {
37911
+ throw new Error("Scout pairing relay URL is not configured.");
37912
+ }
37913
+ state.bonjour = managedRelay ? startBonjourRelayAdvertisement({
37914
+ port: relayPort,
39891
37915
  relayUrl: activeRelayUrl,
37916
+ publicKeyHex
37917
+ }) : null;
37918
+ state.runtime = await startPairingRuntime({
37919
+ relayUrl: connectRelayUrl,
37920
+ advertisedRelayUrl: activeRelayUrl,
37921
+ fallbackRelayUrls: managedRelay?.fallbackRelayUrls,
39892
37922
  relayEvents: {
39893
37923
  onConnecting() {
39894
37924
  emitStatus("connecting", `Connecting to ${activeRelayUrl}`);
@@ -39911,7 +37941,6 @@ async function startSupervisorRuntime(state) {
39911
37941
  if (!payload) {
39912
37942
  throw new Error("Scout pairing runtime did not produce a QR payload.");
39913
37943
  }
39914
- const identity2 = loadOrCreateIdentity();
39915
37944
  writeCurrent(state, {
39916
37945
  status: "connecting",
39917
37946
  statusLabel: "Pairing Ready",
@@ -39928,7 +37957,7 @@ async function startSupervisorRuntime(state) {
39928
37957
  },
39929
37958
  childPid: null
39930
37959
  }, {
39931
- identityFingerprint: bytesToHex2(identity2.publicKey).slice(0, 16),
37960
+ identityFingerprint: publicKeyHex.slice(0, 16),
39932
37961
  trustedPeerCount: trustedPeerCount()
39933
37962
  });
39934
37963
  schedulePairingRefresh(state, payload);
@@ -40002,6 +38031,9 @@ function clearRefreshTimer(state) {
40002
38031
  }
40003
38032
  }
40004
38033
  async function stopSupervisorRuntime(state) {
38034
+ try {
38035
+ state.bonjour?.stop();
38036
+ } catch {}
40005
38037
  try {
40006
38038
  await state.runtime?.stop();
40007
38039
  } catch {}
@@ -40010,6 +38042,57 @@ async function stopSupervisorRuntime(state) {
40010
38042
  } catch {}
40011
38043
  state.runtime = null;
40012
38044
  state.relay = null;
38045
+ state.bonjour = null;
38046
+ }
38047
+ function startBonjourRelayAdvertisement(input) {
38048
+ if (process.platform !== "darwin") {
38049
+ return null;
38050
+ }
38051
+ const scheme = relayScheme(input.relayUrl);
38052
+ const fingerprint = input.publicKeyHex.slice(0, 16);
38053
+ const serviceName = `OpenScout ${fingerprint}`;
38054
+ const args = [
38055
+ "-R",
38056
+ serviceName,
38057
+ BONJOUR_SERVICE_TYPE,
38058
+ "local.",
38059
+ String(input.port),
38060
+ "v=1",
38061
+ `pk=${input.publicKeyHex}`,
38062
+ `fp=${fingerprint}`,
38063
+ `scheme=${scheme}`
38064
+ ];
38065
+ let processRef = null;
38066
+ try {
38067
+ processRef = spawn4("/usr/bin/dns-sd", args, { stdio: "ignore" });
38068
+ processRef.on("error", (error48) => {
38069
+ console.warn(`[pairing] bonjour advertisement failed: ${error48.message}`);
38070
+ });
38071
+ processRef.on("exit", (code, signal) => {
38072
+ if (code !== 0 && signal !== "SIGTERM") {
38073
+ console.warn(`[pairing] bonjour advertisement exited (code=${code ?? "null"}, signal=${signal ?? "null"})`);
38074
+ }
38075
+ });
38076
+ console.log(`[pairing] bonjour advertising ${serviceName} on ${BONJOUR_SERVICE_TYPE} port ${input.port}`);
38077
+ } catch (error48) {
38078
+ const detail = error48 instanceof Error ? error48.message : String(error48);
38079
+ console.warn(`[pairing] bonjour advertisement unavailable: ${detail}`);
38080
+ return null;
38081
+ }
38082
+ return {
38083
+ stop() {
38084
+ processRef?.kill("SIGTERM");
38085
+ processRef = null;
38086
+ }
38087
+ };
38088
+ }
38089
+ function relayScheme(relayUrl) {
38090
+ try {
38091
+ const protocol = new URL(relayUrl).protocol;
38092
+ return protocol === "wss:" ? "wss" : "ws";
38093
+ } catch {
38094
+ return relayUrl.startsWith("wss://") ? "wss" : "ws";
38095
+ }
40013
38096
  }
40014
38097
  function writeCurrent(state, patch, overrides = {}) {
40015
38098
  state.current = writePairingRuntimeSnapshot({