@openscout/scout 0.2.25 → 0.2.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.mjs CHANGED
@@ -7398,6 +7398,35 @@ var init_local_agents = __esm(async () => {
7398
7398
  SUPPORTED_LOCAL_AGENT_HARNESSES = ["claude", "codex"];
7399
7399
  });
7400
7400
 
7401
+ // ../runtime/src/user-config.ts
7402
+ import { existsSync as existsSync6, readFileSync as readFileSync4, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "fs";
7403
+ import { homedir as homedir5 } from "os";
7404
+ import { dirname as dirname6, join as join9 } from "path";
7405
+ function userConfigPath() {
7406
+ return join9(process.env.OPENSCOUT_HOME ?? join9(homedir5(), ".openscout"), "user.json");
7407
+ }
7408
+ function loadUserConfig() {
7409
+ const configPath = userConfigPath();
7410
+ if (!existsSync6(configPath))
7411
+ return {};
7412
+ try {
7413
+ return JSON.parse(readFileSync4(configPath, "utf8"));
7414
+ } catch {
7415
+ return {};
7416
+ }
7417
+ }
7418
+ function saveUserConfig(config) {
7419
+ const configPath = userConfigPath();
7420
+ mkdirSync3(dirname6(configPath), { recursive: true });
7421
+ writeFileSync3(configPath, JSON.stringify(config, null, 2) + `
7422
+ `, "utf8");
7423
+ }
7424
+ function resolveOperatorName() {
7425
+ const config = loadUserConfig();
7426
+ return config.name?.trim() || process.env.OPENSCOUT_OPERATOR_NAME?.trim() || process.env.USER?.trim() || "operator";
7427
+ }
7428
+ var init_user_config = () => {};
7429
+
7401
7430
  // ../../apps/desktop/src/core/broker/paths.ts
7402
7431
  var scoutBrokerPaths, openAiAudioSpeechUrl = "https://api.openai.com/v1/audio/speech";
7403
7432
  var init_paths = __esm(() => {
@@ -7421,7 +7450,7 @@ var init_paths = __esm(() => {
7421
7450
 
7422
7451
  // ../../apps/desktop/src/core/broker/service.ts
7423
7452
  import { mkdir as mkdir6, readFile as readFile6, unlink, writeFile as writeFile6 } from "fs/promises";
7424
- import { basename as basename4, join as join9 } from "path";
7453
+ import { basename as basename4, join as join10 } from "path";
7425
7454
  function buildScoutBrokerUrlFromEnv() {
7426
7455
  const host = process.env.OPENSCOUT_BROKER_HOST ?? DEFAULT_BROKER_HOST2;
7427
7456
  const port = Number.parseInt(process.env.OPENSCOUT_BROKER_PORT ?? String(DEFAULT_BROKER_PORT2), 10);
@@ -7445,7 +7474,7 @@ function resolveScoutAgentName(agentName) {
7445
7474
  if (process.env.OPENSCOUT_AGENT?.trim()) {
7446
7475
  return process.env.OPENSCOUT_AGENT.trim();
7447
7476
  }
7448
- return OPERATOR_ID;
7477
+ return resolveOperatorName();
7449
7478
  }
7450
7479
  async function resolveScoutSenderId(agentName, currentDirectory) {
7451
7480
  if (agentName?.trim()) {
@@ -8423,7 +8452,7 @@ async function listScoutAgents(options = {}) {
8423
8452
  }
8424
8453
  async function loadScoutRelayConfig() {
8425
8454
  try {
8426
- const raw = await readFile6(join9(relayHubDirectory(), "config.json"), "utf8");
8455
+ const raw = await readFile6(join10(relayHubDirectory(), "config.json"), "utf8");
8427
8456
  return JSON.parse(raw);
8428
8457
  } catch {
8429
8458
  return {};
@@ -8445,7 +8474,7 @@ function applyPronunciations(text, pronunciations) {
8445
8474
  async function acquireScoutOnAir(agent, timeoutMs = 30000) {
8446
8475
  const hub = relayHubDirectory();
8447
8476
  await mkdir6(hub, { recursive: true });
8448
- const lockPath = join9(hub, "on-air.lock");
8477
+ const lockPath = join10(hub, "on-air.lock");
8449
8478
  const deadline = Date.now() + timeoutMs;
8450
8479
  while (Date.now() < deadline) {
8451
8480
  try {
@@ -8463,7 +8492,7 @@ async function acquireScoutOnAir(agent, timeoutMs = 30000) {
8463
8492
  }
8464
8493
  async function releaseScoutOnAir() {
8465
8494
  try {
8466
- await unlink(join9(relayHubDirectory(), "on-air.lock"));
8495
+ await unlink(join10(relayHubDirectory(), "on-air.lock"));
8467
8496
  } catch {}
8468
8497
  }
8469
8498
  async function speakScoutText(text, voice) {
@@ -8513,7 +8542,7 @@ async function speakScoutText(text, voice) {
8513
8542
  await new Promise((resolve7) => player.on("close", () => resolve7()));
8514
8543
  }
8515
8544
  function buildScoutEnrollmentPrompt(input) {
8516
- const relayLogPath = join9(relayHubDirectory(), "channel.log");
8545
+ const relayLogPath = join10(relayHubDirectory(), "channel.log");
8517
8546
  const cliCommand = input.cliCommand?.trim() || "scout";
8518
8547
  const task = input.task?.trim();
8519
8548
  return [
@@ -8542,6 +8571,7 @@ var init_service = __esm(async () => {
8542
8571
  init_src();
8543
8572
  init_setup();
8544
8573
  init_support_paths();
8574
+ init_user_config();
8545
8575
  init_paths();
8546
8576
  await init_local_agents();
8547
8577
  BUILT_IN_SCOUT_AGENT_IDS = new Set([SCOUT_AGENT_ID, "builder", "reviewer", "research"]);
@@ -8883,6 +8913,47 @@ var init_card = __esm(async () => {
8883
8913
  ]);
8884
8914
  });
8885
8915
 
8916
+ // ../../apps/desktop/src/cli/commands/config.ts
8917
+ var exports_config = {};
8918
+ __export(exports_config, {
8919
+ runConfigCommand: () => runConfigCommand
8920
+ });
8921
+ async function runConfigCommand(_context, args) {
8922
+ const [subcommand, key, ...rest] = args;
8923
+ if (subcommand === "set" && key === "name" && rest.length > 0) {
8924
+ const name = rest.join(" ").trim();
8925
+ const config = loadUserConfig();
8926
+ config.name = name;
8927
+ saveUserConfig(config);
8928
+ console.log(`Name set to: ${name}`);
8929
+ return;
8930
+ }
8931
+ if (subcommand === "get" && key === "name") {
8932
+ console.log(resolveOperatorName());
8933
+ return;
8934
+ }
8935
+ if (subcommand === "set" && key === "name") {
8936
+ const config = loadUserConfig();
8937
+ delete config.name;
8938
+ saveUserConfig(config);
8939
+ console.log(`Name reset to default: ${resolveOperatorName()}`);
8940
+ return;
8941
+ }
8942
+ if (!subcommand || subcommand === "show") {
8943
+ const config = loadUserConfig();
8944
+ const name = resolveOperatorName();
8945
+ console.log(`name: ${name}${config.name ? "" : " (default)"}`);
8946
+ return;
8947
+ }
8948
+ console.error("usage: scout config [show]");
8949
+ console.error(" scout config set name <value>");
8950
+ console.error(" scout config get name");
8951
+ process.exit(1);
8952
+ }
8953
+ var init_config = __esm(() => {
8954
+ init_user_config();
8955
+ });
8956
+
8886
8957
  // ../../apps/desktop/src/ui/terminal/agents.ts
8887
8958
  function formatUptime(startedAt) {
8888
8959
  const now = Math.floor(Date.now() / 1000);
@@ -8972,24 +9043,24 @@ var init_down = __esm(async () => {
8972
9043
 
8973
9044
  // ../../apps/desktop/src/app/host/runtime-service-client.ts
8974
9045
  import { spawn as spawn3 } from "child_process";
8975
- import { basename as basename5, dirname as dirname6, join as join10 } from "path";
8976
- import { existsSync as existsSync6 } from "fs";
9046
+ import { basename as basename5, dirname as dirname7, join as join11 } from "path";
9047
+ import { existsSync as existsSync7 } from "fs";
8977
9048
  import { fileURLToPath as fileURLToPath5 } from "url";
8978
- import { homedir as homedir5 } from "os";
9049
+ import { homedir as homedir6 } from "os";
8979
9050
  function tryWhich(executableName) {
8980
9051
  const pathEnv = process.env.PATH ?? "";
8981
9052
  const sep = process.platform === "win32" ? ";" : ":";
8982
9053
  for (const dir of pathEnv.split(sep)) {
8983
9054
  if (!dir)
8984
9055
  continue;
8985
- const candidate = join10(dir, executableName);
8986
- if (existsSync6(candidate)) {
9056
+ const candidate = join11(dir, executableName);
9057
+ if (existsSync7(candidate)) {
8987
9058
  return candidate;
8988
9059
  }
8989
9060
  if (process.platform === "win32") {
8990
9061
  for (const ext of [".cmd", ".exe", ".bat"]) {
8991
9062
  const withExt = candidate + ext;
8992
- if (existsSync6(withExt))
9063
+ if (existsSync7(withExt))
8993
9064
  return withExt;
8994
9065
  }
8995
9066
  }
@@ -8997,30 +9068,30 @@ function tryWhich(executableName) {
8997
9068
  return null;
8998
9069
  }
8999
9070
  function findNodeModulesRuntimeBin() {
9000
- const runtimeBinRel = join10("node_modules", "@openscout", "runtime", "bin", "openscout-runtime.mjs");
9001
- let dir = dirname6(fileURLToPath5(import.meta.url));
9071
+ const runtimeBinRel = join11("node_modules", "@openscout", "runtime", "bin", "openscout-runtime.mjs");
9072
+ let dir = dirname7(fileURLToPath5(import.meta.url));
9002
9073
  for (let i = 0;i < 24; i++) {
9003
- const candidate = join10(dir, runtimeBinRel);
9004
- if (existsSync6(candidate))
9074
+ const candidate = join11(dir, runtimeBinRel);
9075
+ if (existsSync7(candidate))
9005
9076
  return candidate;
9006
- const parent = dirname6(dir);
9077
+ const parent = dirname7(dir);
9007
9078
  if (parent === dir)
9008
9079
  break;
9009
9080
  dir = parent;
9010
9081
  }
9011
- const bunGlobal = join10(homedir5(), ".bun", "install", "global", "node_modules", "@openscout", "runtime", "bin", "openscout-runtime.mjs");
9012
- if (existsSync6(bunGlobal))
9082
+ const bunGlobal = join11(homedir6(), ".bun", "install", "global", "node_modules", "@openscout", "runtime", "bin", "openscout-runtime.mjs");
9083
+ if (existsSync7(bunGlobal))
9013
9084
  return bunGlobal;
9014
9085
  return null;
9015
9086
  }
9016
9087
  function findMonorepoOpenscoutRuntimeBin() {
9017
9088
  let dir = process.cwd();
9018
9089
  for (let i = 0;i < 24; i++) {
9019
- const candidate = join10(dir, "packages", "runtime", "bin", "openscout-runtime.mjs");
9020
- if (existsSync6(candidate)) {
9090
+ const candidate = join11(dir, "packages", "runtime", "bin", "openscout-runtime.mjs");
9091
+ if (existsSync7(candidate)) {
9021
9092
  return candidate;
9022
9093
  }
9023
- const parent = dirname6(dir);
9094
+ const parent = dirname7(dir);
9024
9095
  if (parent === dir)
9025
9096
  break;
9026
9097
  dir = parent;
@@ -9030,7 +9101,7 @@ function findMonorepoOpenscoutRuntimeBin() {
9030
9101
  function resolveJavaScriptRuntimeExecutable() {
9031
9102
  const explicit = process.env.OPENSCOUT_RUNTIME_NODE_BIN?.trim();
9032
9103
  if (explicit) {
9033
- if (existsSync6(explicit)) {
9104
+ if (existsSync7(explicit)) {
9034
9105
  return explicit;
9035
9106
  }
9036
9107
  const found = tryWhich(explicit);
@@ -9056,7 +9127,7 @@ function resolveJavaScriptRuntimeExecutable() {
9056
9127
  function resolveRuntimeServiceEntrypoint() {
9057
9128
  const explicit = process.env.OPENSCOUT_RUNTIME_BIN?.trim();
9058
9129
  if (explicit) {
9059
- if (existsSync6(explicit)) {
9130
+ if (existsSync7(explicit)) {
9060
9131
  return explicit;
9061
9132
  }
9062
9133
  const found = tryWhich(explicit);
@@ -9149,9 +9220,9 @@ var init_runtime_service_client = () => {};
9149
9220
  // ../../apps/desktop/src/core/setup/command-lock.ts
9150
9221
  import { mkdir as mkdir7, open, readFile as readFile7, rm as rm5 } from "fs/promises";
9151
9222
  import { hostname as hostname2 } from "os";
9152
- import { dirname as dirname7, join as join11 } from "path";
9223
+ import { dirname as dirname8, join as join12 } from "path";
9153
9224
  function scoutCoreCommandLockPath() {
9154
- return join11(resolveOpenScoutSupportPaths().runtimeDirectory, "locks", SCOUT_CORE_COMMAND_LOCK_FILE);
9225
+ return join12(resolveOpenScoutSupportPaths().runtimeDirectory, "locks", SCOUT_CORE_COMMAND_LOCK_FILE);
9155
9226
  }
9156
9227
  function isProcessAlive(pid) {
9157
9228
  if (!Number.isInteger(pid) || pid <= 0) {
@@ -9191,7 +9262,7 @@ async function readLockPayload(lockPath) {
9191
9262
  }
9192
9263
  async function acquireScoutCoreCommandLock(command) {
9193
9264
  const lockPath = scoutCoreCommandLockPath();
9194
- await mkdir7(dirname7(lockPath), { recursive: true });
9265
+ await mkdir7(dirname8(lockPath), { recursive: true });
9195
9266
  for (let attempt = 0;attempt < 2; attempt += 1) {
9196
9267
  const payload = {
9197
9268
  command,
@@ -9323,35 +9394,35 @@ var init_service3 = __esm(() => {
9323
9394
  });
9324
9395
 
9325
9396
  // ../../apps/desktop/src/shared/paths.ts
9326
- import { existsSync as existsSync7, readFileSync as readFileSync4 } from "fs";
9327
- import { dirname as dirname8, join as join12, resolve as resolve7 } from "path";
9397
+ import { existsSync as existsSync8, readFileSync as readFileSync5 } from "fs";
9398
+ import { dirname as dirname9, join as join13, resolve as resolve7 } from "path";
9328
9399
  import { fileURLToPath as fileURLToPath6 } from "url";
9329
9400
  function looksLikeWorkspaceRoot(candidate) {
9330
- const packageJsonPath = join12(candidate, "package.json");
9331
- if (!existsSync7(packageJsonPath)) {
9401
+ const packageJsonPath = join13(candidate, "package.json");
9402
+ if (!existsSync8(packageJsonPath)) {
9332
9403
  return false;
9333
9404
  }
9334
9405
  try {
9335
- const parsed = JSON.parse(readFileSync4(packageJsonPath, "utf8"));
9406
+ const parsed = JSON.parse(readFileSync5(packageJsonPath, "utf8"));
9336
9407
  return Array.isArray(parsed.workspaces);
9337
9408
  } catch {
9338
9409
  return false;
9339
9410
  }
9340
9411
  }
9341
9412
  function looksLikePackagedAppRoot(candidate) {
9342
- const packageJsonPath = join12(candidate, "package.json");
9343
- if (!existsSync7(packageJsonPath)) {
9413
+ const packageJsonPath = join13(candidate, "package.json");
9414
+ if (!existsSync8(packageJsonPath)) {
9344
9415
  return false;
9345
9416
  }
9346
9417
  try {
9347
- const parsed = JSON.parse(readFileSync4(packageJsonPath, "utf8"));
9418
+ const parsed = JSON.parse(readFileSync5(packageJsonPath, "utf8"));
9348
9419
  return parsed.name === "@openscout/scout" || parsed.name === "@openscout/cli";
9349
9420
  } catch {
9350
9421
  return false;
9351
9422
  }
9352
9423
  }
9353
9424
  function looksLikeSourceAppRoot(candidate) {
9354
- return existsSync7(join12(candidate, "bin", "scout.ts"));
9425
+ return existsSync8(join13(candidate, "bin", "scout.ts"));
9355
9426
  }
9356
9427
  function findMatchingAncestor(startDirectory, predicate) {
9357
9428
  let current = resolve7(startDirectory);
@@ -9359,7 +9430,7 @@ function findMatchingAncestor(startDirectory, predicate) {
9359
9430
  if (predicate(current)) {
9360
9431
  return current;
9361
9432
  }
9362
- const parent = dirname8(current);
9433
+ const parent = dirname9(current);
9363
9434
  if (parent === current) {
9364
9435
  return null;
9365
9436
  }
@@ -9367,7 +9438,7 @@ function findMatchingAncestor(startDirectory, predicate) {
9367
9438
  }
9368
9439
  }
9369
9440
  function defaultModuleDirectory() {
9370
- return dirname8(fileURLToPath6(import.meta.url));
9441
+ return dirname9(fileURLToPath6(import.meta.url));
9371
9442
  }
9372
9443
  function uniqueResolutionStarts(options) {
9373
9444
  const starts = [
@@ -9671,8 +9742,8 @@ var exports_env = {};
9671
9742
  __export(exports_env, {
9672
9743
  runEnvCommand: () => runEnvCommand
9673
9744
  });
9674
- import { existsSync as existsSync8 } from "fs";
9675
- import { join as join13 } from "path";
9745
+ import { existsSync as existsSync9 } from "fs";
9746
+ import { join as join14 } from "path";
9676
9747
  function resolveCommandOnPath(command, env) {
9677
9748
  const pathValue = env.PATH ?? "";
9678
9749
  for (const directory of pathValue.split(":")) {
@@ -9680,8 +9751,8 @@ function resolveCommandOnPath(command, env) {
9680
9751
  if (!trimmed) {
9681
9752
  continue;
9682
9753
  }
9683
- const candidate = join13(trimmed, command);
9684
- if (existsSync8(candidate)) {
9754
+ const candidate = join14(trimmed, command);
9755
+ if (existsSync9(candidate)) {
9685
9756
  return candidate;
9686
9757
  }
9687
9758
  }
@@ -9689,11 +9760,11 @@ function resolveCommandOnPath(command, env) {
9689
9760
  }
9690
9761
  function resolveScoutBinPath(appRoot) {
9691
9762
  const candidates = [
9692
- join13(appRoot, "bin", "scout.ts"),
9693
- join13(appRoot, "bin", "scout.mjs")
9763
+ join14(appRoot, "bin", "scout.ts"),
9764
+ join14(appRoot, "bin", "scout.mjs")
9694
9765
  ];
9695
9766
  for (const candidate of candidates) {
9696
- if (existsSync8(candidate)) {
9767
+ if (existsSync9(candidate)) {
9697
9768
  return candidate;
9698
9769
  }
9699
9770
  }
@@ -10216,11 +10287,11 @@ var init_mesh = __esm(async () => {
10216
10287
  });
10217
10288
 
10218
10289
  // ../../apps/desktop/src/core/pairing/runtime/config.ts
10219
- import { existsSync as existsSync9, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
10220
- import { homedir as homedir6 } from "os";
10290
+ import { existsSync as existsSync10, mkdirSync as mkdirSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
10291
+ import { homedir as homedir7 } from "os";
10221
10292
  import path from "path";
10222
10293
  function pairingPaths() {
10223
- const rootDir = path.join(homedir6(), ".scout/pairing");
10294
+ const rootDir = path.join(homedir7(), ".scout/pairing");
10224
10295
  return {
10225
10296
  rootDir,
10226
10297
  configPath: path.join(rootDir, "config.json"),
@@ -10233,11 +10304,11 @@ function pairingPaths() {
10233
10304
  }
10234
10305
  function loadPairingConfig() {
10235
10306
  const { configPath } = pairingPaths();
10236
- if (!existsSync9(configPath)) {
10307
+ if (!existsSync10(configPath)) {
10237
10308
  return {};
10238
10309
  }
10239
10310
  try {
10240
- const payload = JSON.parse(readFileSync5(configPath, "utf8"));
10311
+ const payload = JSON.parse(readFileSync6(configPath, "utf8"));
10241
10312
  return typeof payload === "object" && payload ? payload : {};
10242
10313
  } catch {
10243
10314
  return {};
@@ -10254,7 +10325,7 @@ function resolvedPairingConfig() {
10254
10325
  };
10255
10326
  }
10256
10327
  var PAIRING_QR_TTL_MS;
10257
- var init_config = __esm(() => {
10328
+ var init_config2 = __esm(() => {
10258
10329
  PAIRING_QR_TTL_MS = 5 * 60 * 1000;
10259
10330
  });
10260
10331
 
@@ -12320,17 +12391,17 @@ var init_noise = __esm(() => {
12320
12391
  });
12321
12392
 
12322
12393
  // ../../apps/desktop/src/core/pairing/runtime/security/identity.ts
12323
- import { existsSync as existsSync10, mkdirSync as mkdirSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
12324
- import { join as join14 } from "path";
12325
- import { homedir as homedir7 } from "os";
12394
+ import { existsSync as existsSync11, mkdirSync as mkdirSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
12395
+ import { join as join15 } from "path";
12396
+ import { homedir as homedir8 } from "os";
12326
12397
  function loadOrCreateIdentity() {
12327
- if (existsSync10(IDENTITY_FILE)) {
12398
+ if (existsSync11(IDENTITY_FILE)) {
12328
12399
  return loadIdentity();
12329
12400
  }
12330
12401
  return createAndSaveIdentity();
12331
12402
  }
12332
12403
  function loadIdentity() {
12333
- const data = JSON.parse(readFileSync6(IDENTITY_FILE, "utf8"));
12404
+ const data = JSON.parse(readFileSync7(IDENTITY_FILE, "utf8"));
12334
12405
  return {
12335
12406
  publicKey: hexToBytes2(data.publicKey),
12336
12407
  privateKey: hexToBytes2(data.privateKey)
@@ -12338,26 +12409,26 @@ function loadIdentity() {
12338
12409
  }
12339
12410
  function createAndSaveIdentity() {
12340
12411
  const keyPair = generateKeyPair();
12341
- mkdirSync4(PAIRING_DIR, { recursive: true });
12412
+ mkdirSync5(PAIRING_DIR, { recursive: true });
12342
12413
  const data = {
12343
12414
  publicKey: bytesToHex2(keyPair.publicKey),
12344
12415
  privateKey: bytesToHex2(keyPair.privateKey),
12345
12416
  createdAt: new Date().toISOString()
12346
12417
  };
12347
- writeFileSync4(IDENTITY_FILE, JSON.stringify(data, null, 2), { mode: 384 });
12418
+ writeFileSync5(IDENTITY_FILE, JSON.stringify(data, null, 2), { mode: 384 });
12348
12419
  return keyPair;
12349
12420
  }
12350
12421
  function loadTrustedPeers() {
12351
- if (!existsSync10(TRUSTED_PEERS_FILE))
12422
+ if (!existsSync11(TRUSTED_PEERS_FILE))
12352
12423
  return new Map;
12353
- const data = JSON.parse(readFileSync6(TRUSTED_PEERS_FILE, "utf8"));
12424
+ const data = JSON.parse(readFileSync7(TRUSTED_PEERS_FILE, "utf8"));
12354
12425
  return new Map(data.map((p) => [p.publicKey, p]));
12355
12426
  }
12356
12427
  function saveTrustedPeer(peer) {
12357
12428
  const peers = loadTrustedPeers();
12358
12429
  peers.set(peer.publicKey, peer);
12359
- mkdirSync4(PAIRING_DIR, { recursive: true });
12360
- writeFileSync4(TRUSTED_PEERS_FILE, JSON.stringify([...peers.values()], null, 2), { mode: 384 });
12430
+ mkdirSync5(PAIRING_DIR, { recursive: true });
12431
+ writeFileSync5(TRUSTED_PEERS_FILE, JSON.stringify([...peers.values()], null, 2), { mode: 384 });
12361
12432
  }
12362
12433
  function isTrustedPeer(publicKeyHex) {
12363
12434
  return loadTrustedPeers().has(publicKeyHex);
@@ -12384,9 +12455,9 @@ function hexToBytes2(hex) {
12384
12455
  var PAIRING_DIR, IDENTITY_FILE, TRUSTED_PEERS_FILE, QR_VERSION = 1, QR_EXPIRY_MS;
12385
12456
  var init_identity = __esm(() => {
12386
12457
  init_noise();
12387
- PAIRING_DIR = join14(homedir7(), ".scout/pairing");
12388
- IDENTITY_FILE = join14(PAIRING_DIR, "identity.json");
12389
- TRUSTED_PEERS_FILE = join14(PAIRING_DIR, "trusted-peers.json");
12458
+ PAIRING_DIR = join15(homedir8(), ".scout/pairing");
12459
+ IDENTITY_FILE = join15(PAIRING_DIR, "identity.json");
12460
+ TRUSTED_PEERS_FILE = join15(PAIRING_DIR, "trusted-peers.json");
12390
12461
  QR_EXPIRY_MS = 5 * 60 * 1000;
12391
12462
  });
12392
12463
 
@@ -12531,14 +12602,14 @@ var init_security2 = __esm(() => {
12531
12602
  });
12532
12603
 
12533
12604
  // ../../apps/desktop/src/core/pairing/runtime/runtime-state.ts
12534
- import { existsSync as existsSync11, mkdirSync as mkdirSync5, readFileSync as readFileSync7, renameSync, unlinkSync, writeFileSync as writeFileSync5 } from "fs";
12605
+ import { existsSync as existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync8, renameSync, unlinkSync, writeFileSync as writeFileSync6 } from "fs";
12535
12606
  function readPairingRuntimeSnapshot() {
12536
12607
  const { runtimeStatePath } = pairingPaths();
12537
- if (!existsSync11(runtimeStatePath)) {
12608
+ if (!existsSync12(runtimeStatePath)) {
12538
12609
  return null;
12539
12610
  }
12540
12611
  try {
12541
- const parsed = JSON.parse(readFileSync7(runtimeStatePath, "utf8"));
12612
+ const parsed = JSON.parse(readFileSync8(runtimeStatePath, "utf8"));
12542
12613
  return parsed?.version === 1 ? parsed : null;
12543
12614
  } catch {
12544
12615
  return null;
@@ -12556,7 +12627,7 @@ function isProcessRunning(pid) {
12556
12627
  }
12557
12628
  }
12558
12629
  var init_runtime_state = __esm(() => {
12559
- init_config();
12630
+ init_config2();
12560
12631
  init_security2();
12561
12632
  });
12562
12633
 
@@ -13001,8 +13072,8 @@ Referenced files: ${prompt.files.join(", ")}` });
13001
13072
  });
13002
13073
 
13003
13074
  // ../../apps/desktop/src/core/pairing/runtime/adapters/codex.ts
13004
- import { homedir as homedir8 } from "os";
13005
- import { join as join15 } from "path";
13075
+ import { homedir as homedir9 } from "os";
13076
+ import { join as join16 } from "path";
13006
13077
  var CodexAdapter, createAdapter2 = (config) => new CodexAdapter(config);
13007
13078
  var init_codex = __esm(() => {
13008
13079
  init_codex_app_server();
@@ -13102,14 +13173,14 @@ var init_codex = __esm(() => {
13102
13173
  this.setStatus("closed");
13103
13174
  }
13104
13175
  get codexOptions() {
13105
- const runtimeRoot = join15(homedir8(), ".scout/pairing", "codex", this.session.id);
13176
+ const runtimeRoot = join16(homedir9(), ".scout/pairing", "codex", this.session.id);
13106
13177
  return {
13107
13178
  agentName: this.session.name,
13108
13179
  sessionId: this.session.id,
13109
13180
  cwd: this.config.cwd ?? process.cwd(),
13110
13181
  systemPrompt: this.systemPrompt,
13111
- runtimeDirectory: join15(runtimeRoot, "runtime"),
13112
- logsDirectory: join15(runtimeRoot, "logs")
13182
+ runtimeDirectory: join16(runtimeRoot, "runtime"),
13183
+ logsDirectory: join16(runtimeRoot, "logs")
13113
13184
  };
13114
13185
  }
13115
13186
  get systemPrompt() {
@@ -14574,9 +14645,9 @@ class StateTracker {
14574
14645
  }
14575
14646
 
14576
14647
  // ../../apps/desktop/src/core/pairing/runtime/bridge/log.ts
14577
- import { appendFileSync, mkdirSync as mkdirSync6 } from "fs";
14578
- import { join as join16 } from "path";
14579
- import { homedir as homedir9 } from "os";
14648
+ import { appendFileSync, mkdirSync as mkdirSync7 } from "fs";
14649
+ import { join as join17 } from "path";
14650
+ import { homedir as homedir10 } from "os";
14580
14651
  function write(level, category, message, data) {
14581
14652
  const ts = new Date().toISOString().slice(11, 23);
14582
14653
  const lvl = level.toUpperCase().padEnd(5);
@@ -14592,9 +14663,9 @@ function write(level, category, message, data) {
14592
14663
  }
14593
14664
  var LOG_DIR, LOG_FILE, log;
14594
14665
  var init_log = __esm(() => {
14595
- LOG_DIR = join16(homedir9(), ".scout/pairing");
14596
- LOG_FILE = join16(LOG_DIR, "bridge.log");
14597
- mkdirSync6(LOG_DIR, { recursive: true });
14666
+ LOG_DIR = join17(homedir10(), ".scout/pairing");
14667
+ LOG_FILE = join17(LOG_DIR, "bridge.log");
14668
+ mkdirSync7(LOG_DIR, { recursive: true });
14598
14669
  log = {
14599
14670
  debug: (cat, msg, data) => write("debug", cat, msg, data),
14600
14671
  info: (cat, msg, data) => write("info", cat, msg, data),
@@ -14756,15 +14827,15 @@ var init_bridge = __esm(() => {
14756
14827
  });
14757
14828
 
14758
14829
  // ../../apps/desktop/src/core/pairing/runtime/bridge/config.ts
14759
- import { existsSync as existsSync12, readFileSync as readFileSync8 } from "fs";
14760
- import { join as join17 } from "path";
14761
- import { homedir as homedir10 } from "os";
14830
+ import { existsSync as existsSync13, readFileSync as readFileSync9 } from "fs";
14831
+ import { join as join18 } from "path";
14832
+ import { homedir as homedir11 } from "os";
14762
14833
  function loadConfigFile() {
14763
- if (!existsSync12(CONFIG_FILE)) {
14834
+ if (!existsSync13(CONFIG_FILE)) {
14764
14835
  return {};
14765
14836
  }
14766
14837
  try {
14767
- const raw = readFileSync8(CONFIG_FILE, "utf8");
14838
+ const raw = readFileSync9(CONFIG_FILE, "utf8");
14768
14839
  const parsed = JSON.parse(raw);
14769
14840
  return parsed;
14770
14841
  } catch (err) {
@@ -14816,22 +14887,22 @@ function resolveConfig() {
14816
14887
  return resolveConfigLayers(file, cli);
14817
14888
  }
14818
14889
  var DEFAULTS, CONFIG_DIR, CONFIG_FILE;
14819
- var init_config2 = __esm(() => {
14890
+ var init_config3 = __esm(() => {
14820
14891
  DEFAULTS = {
14821
14892
  port: 7888,
14822
14893
  secure: true
14823
14894
  };
14824
- CONFIG_DIR = join17(homedir10(), ".scout/pairing");
14825
- CONFIG_FILE = join17(CONFIG_DIR, "config.json");
14895
+ CONFIG_DIR = join18(homedir11(), ".scout/pairing");
14896
+ CONFIG_FILE = join18(CONFIG_DIR, "config.json");
14826
14897
  });
14827
14898
 
14828
14899
  // ../../apps/desktop/src/core/pairing/runtime/bridge/fileserver.ts
14829
14900
  import { isAbsolute as isAbsolute2 } from "path";
14830
- import { homedir as homedir11 } from "os";
14901
+ import { homedir as homedir12 } from "os";
14831
14902
  function isAllowedPath(filePath) {
14832
14903
  if (!isAbsolute2(filePath))
14833
14904
  return false;
14834
- const relToHome = filePath.slice(homedir11().length + 1);
14905
+ const relToHome = filePath.slice(homedir12().length + 1);
14835
14906
  if (relToHome.startsWith(".") && !relToHome.startsWith(".claude") && !relToHome.startsWith(".scout/pairing")) {
14836
14907
  return false;
14837
14908
  }
@@ -14890,7 +14961,7 @@ function serveFile(url) {
14890
14961
  }
14891
14962
  var ALLOWED_ROOTS;
14892
14963
  var init_fileserver = __esm(() => {
14893
- ALLOWED_ROOTS = [homedir11(), "/tmp"];
14964
+ ALLOWED_ROOTS = [homedir12(), "/tmp"];
14894
14965
  });
14895
14966
 
14896
14967
  // ../../apps/desktop/src/core/mobile/service.ts
@@ -15170,7 +15241,35 @@ async function getScoutMobileSessionSnapshot(conversationId, options = {}, curre
15170
15241
  const { snapshot } = broker;
15171
15242
  const conversation = snapshot.conversations[conversationId];
15172
15243
  if (!conversation) {
15173
- throw new Error(`Unknown mobile session "${conversationId}".`);
15244
+ const inferredAgentId = conversationId.startsWith("dm.operator.") ? conversationId.slice("dm.operator.".length) : null;
15245
+ const agent2 = inferredAgentId ? snapshot.agents[inferredAgentId] : null;
15246
+ const endpoint2 = inferredAgentId ? endpointForAgent(snapshot, inferredAgentId) : null;
15247
+ const agentName = agent2 ? agentDisplayName(snapshot, inferredAgentId) : inferredAgentId ?? conversationId;
15248
+ return {
15249
+ session: {
15250
+ id: conversationId,
15251
+ name: agentName,
15252
+ adapterType: endpoint2?.harness ?? "relay",
15253
+ status: endpoint2?.state === "offline" ? "idle" : "active",
15254
+ cwd: endpoint2?.projectRoot ?? endpoint2?.cwd ?? null,
15255
+ model: typeof endpoint2?.metadata?.model === "string" ? endpoint2.metadata.model : null,
15256
+ providerMeta: {
15257
+ conversationId,
15258
+ conversationKind: "direct",
15259
+ agentId: inferredAgentId,
15260
+ workspaceRoot: endpoint2?.projectRoot ?? endpoint2?.cwd ?? null,
15261
+ harness: endpoint2?.harness ?? null,
15262
+ selector: agent2?.selector ?? null,
15263
+ defaultSelector: agent2?.defaultSelector ?? null,
15264
+ project: agentName,
15265
+ currentBranch: metadataString4(endpoint2?.metadata, "branch") ?? metadataString4(endpoint2?.metadata, "workspaceQualifier") ?? metadataString4(agent2?.metadata, "branch") ?? metadataString4(agent2?.metadata, "workspaceQualifier"),
15266
+ workspaceQualifier: metadataString4(endpoint2?.metadata, "workspaceQualifier") ?? metadataString4(agent2?.metadata, "workspaceQualifier")
15267
+ }
15268
+ },
15269
+ history: { hasOlder: false, oldestTurnId: null, newestTurnId: null },
15270
+ turns: [],
15271
+ currentTurnId: null
15272
+ };
15174
15273
  }
15175
15274
  const directAgentId = conversation.kind === "direct" ? conversation.participantIds.find((participantId) => participantId !== "operator") ?? null : null;
15176
15275
  const endpoint = directAgentId ? endpointForAgent(snapshot, directAgentId) : null;
@@ -15365,20 +15464,20 @@ async function deriveNewAgentName(projectName, branch, harness) {
15365
15464
  }
15366
15465
  async function createGitWorktree(projectRoot, agentName) {
15367
15466
  const { execSync: execSync2 } = await import("child_process");
15368
- const { join: join18 } = await import("path");
15369
- const { mkdirSync: mkdirSync7, existsSync: existsSync13 } = await import("fs");
15467
+ const { join: join19 } = await import("path");
15468
+ const { mkdirSync: mkdirSync8, existsSync: existsSync14 } = await import("fs");
15370
15469
  try {
15371
15470
  execSync2("git rev-parse --git-dir", { cwd: projectRoot, stdio: "pipe" });
15372
15471
  } catch {
15373
15472
  return null;
15374
15473
  }
15375
15474
  const branchName = `scout/${agentName}`;
15376
- const worktreeDir = join18(projectRoot, ".scout-worktrees");
15377
- const worktreePath = join18(worktreeDir, agentName);
15378
- if (existsSync13(worktreePath)) {
15475
+ const worktreeDir = join19(projectRoot, ".scout-worktrees");
15476
+ const worktreePath = join19(worktreeDir, agentName);
15477
+ if (existsSync14(worktreePath)) {
15379
15478
  return { path: worktreePath, branch: branchName };
15380
15479
  }
15381
- mkdirSync7(worktreeDir, { recursive: true });
15480
+ mkdirSync8(worktreeDir, { recursive: true });
15382
15481
  try {
15383
15482
  execSync2(`git worktree add -b "${branchName}" "${worktreePath}"`, { cwd: projectRoot, stdio: "pipe" });
15384
15483
  return { path: worktreePath, branch: branchName };
@@ -15417,10 +15516,10 @@ var init_service5 = __esm(async () => {
15417
15516
  });
15418
15517
 
15419
15518
  // ../../apps/desktop/src/core/pairing/runtime/bridge/server.ts
15420
- import { readdirSync, readFileSync as readFileSync9, realpathSync, statSync as statSync2 } from "fs";
15519
+ import { readdirSync, readFileSync as readFileSync10, realpathSync, statSync as statSync2 } from "fs";
15421
15520
  import { execSync as execSync2 } from "child_process";
15422
- import { basename as basename7, isAbsolute as isAbsolute3, join as join18, relative as relative2 } from "path";
15423
- import { homedir as homedir12 } from "os";
15521
+ import { basename as basename7, isAbsolute as isAbsolute3, join as join19, relative as relative2 } from "path";
15522
+ import { homedir as homedir13 } from "os";
15424
15523
  async function handleRPC(bridge, req, deviceId) {
15425
15524
  const rpcStart = Date.now();
15426
15525
  const paramsSnippet = summarizeRPCParams(req.method, req.params);
@@ -15713,7 +15812,7 @@ async function handleRPCInner(bridge, req, deviceId) {
15713
15812
  return { id: req.id, error: { code: -32000, message: "Only .jsonl files can be read" } };
15714
15813
  }
15715
15814
  try {
15716
- const content = readFileSync9(p.path, "utf-8");
15815
+ const content = readFileSync10(p.path, "utf-8");
15717
15816
  const lines = content.split(`
15718
15817
  `).filter((l) => l.trim().length > 0);
15719
15818
  const trimmed = lines.length > 500 ? lines.slice(-500) : lines;
@@ -15831,13 +15930,13 @@ function resolveMobileCurrentDirectory() {
15831
15930
  }
15832
15931
  }
15833
15932
  function resolveWorkspaceRoot(root) {
15834
- const expandedRoot = root.replace(/^~/, homedir12());
15933
+ const expandedRoot = root.replace(/^~/, homedir13());
15835
15934
  return realpathSync(expandedRoot);
15836
15935
  }
15837
15936
  function resolveWorkspacePath(root, requestedPath) {
15838
15937
  const normalizedRoot = resolveWorkspaceRoot(root);
15839
- const expandedPath = requestedPath?.replace(/^~/, homedir12());
15840
- const candidate = expandedPath ? isAbsolute3(expandedPath) ? expandedPath : join18(normalizedRoot, expandedPath) : normalizedRoot;
15938
+ const expandedPath = requestedPath?.replace(/^~/, homedir13());
15939
+ const candidate = expandedPath ? isAbsolute3(expandedPath) ? expandedPath : join19(normalizedRoot, expandedPath) : normalizedRoot;
15841
15940
  const resolvedCandidate = realpathSync(candidate);
15842
15941
  const rel = relative2(normalizedRoot, resolvedCandidate);
15843
15942
  if (rel === "" || !rel.startsWith("..") && !isAbsolute3(rel)) {
@@ -15852,7 +15951,7 @@ function listDirectories(dirPath) {
15852
15951
  continue;
15853
15952
  if (name === "node_modules" || name === ".build" || name === "target")
15854
15953
  continue;
15855
- const fullPath = join18(dirPath, name);
15954
+ const fullPath = join19(dirPath, name);
15856
15955
  try {
15857
15956
  const stat4 = statSync2(fullPath);
15858
15957
  if (!stat4.isDirectory())
@@ -15875,7 +15974,7 @@ function listDirectories(dirPath) {
15875
15974
  return entries.sort((a, b) => a.name.localeCompare(b.name));
15876
15975
  }
15877
15976
  async function discoverSessionFiles(maxAgeDays, limit) {
15878
- const home = homedir12();
15977
+ const home = homedir13();
15879
15978
  const results = [];
15880
15979
  const searchPaths = [
15881
15980
  { pattern: `${home}/.claude/projects`, agent: "claude-code" },
@@ -15972,7 +16071,7 @@ function detectAgent(filePath) {
15972
16071
  var MARKER_FILES;
15973
16072
  var init_server = __esm(async () => {
15974
16073
  init_log();
15975
- init_config2();
16074
+ init_config3();
15976
16075
  init_security();
15977
16076
  await init_service5();
15978
16077
  MARKER_FILES = [
@@ -30781,15 +30880,16 @@ var init_zod = __esm(() => {
30781
30880
 
30782
30881
  // ../../apps/desktop/src/server/db-queries.ts
30783
30882
  import { Database } from "bun:sqlite";
30784
- import { homedir as homedir13 } from "os";
30785
- import { join as join19 } from "path";
30883
+ import { homedir as homedir14 } from "os";
30884
+ import { join as join20 } from "path";
30786
30885
  function resolveDbPath() {
30787
- const controlHome = process.env.OPENSCOUT_CONTROL_HOME ?? join19(homedir13(), ".openscout", "control-plane");
30788
- return join19(controlHome, "control-plane.sqlite");
30886
+ const controlHome = process.env.OPENSCOUT_CONTROL_HOME ?? join20(homedir14(), ".openscout", "control-plane");
30887
+ return join20(controlHome, "control-plane.sqlite");
30789
30888
  }
30790
30889
  function db() {
30791
30890
  if (!_db) {
30792
30891
  _db = new Database(resolveDbPath(), { readonly: true });
30892
+ _db.exec("PRAGMA busy_timeout = 5000");
30793
30893
  _db.exec("PRAGMA journal_mode = WAL");
30794
30894
  }
30795
30895
  return _db;
@@ -30944,16 +31044,96 @@ function queryMobileWorkspaces(limit = 50) {
30944
31044
  }
30945
31045
  return results;
30946
31046
  }
31047
+ function queryMobileAgentDetail(agentId) {
31048
+ const row = db().prepare(`SELECT
31049
+ a.id,
31050
+ ac.display_name,
31051
+ a.default_selector,
31052
+ a.wake_policy,
31053
+ a.capabilities_json,
31054
+ a.metadata_json,
31055
+ ep.harness,
31056
+ ep.transport,
31057
+ ep.state,
31058
+ ep.project_root,
31059
+ ep.cwd,
31060
+ ep.session_id,
31061
+ ep.updated_at
31062
+ FROM agents a
31063
+ JOIN actors ac ON ac.id = a.id
31064
+ LEFT JOIN agent_endpoints ep ON ep.agent_id = a.id
31065
+ WHERE a.id = ?`).get(agentId);
31066
+ if (!row)
31067
+ return null;
31068
+ let meta3 = {};
31069
+ try {
31070
+ meta3 = row.metadata_json ? JSON.parse(row.metadata_json) : {};
31071
+ } catch {}
31072
+ let capabilities = [];
31073
+ try {
31074
+ capabilities = row.capabilities_json ? JSON.parse(row.capabilities_json) : [];
31075
+ } catch {}
31076
+ const workingAgentIds = new Set(db().prepare(`SELECT DISTINCT target_agent_id FROM flights
31077
+ WHERE state NOT IN ('completed','failed','cancelled')`).all().map((r) => r.target_agent_id));
31078
+ const activeFlights = db().prepare(`SELECT id, state, summary, started_at
31079
+ FROM flights
31080
+ WHERE target_agent_id = ? AND state NOT IN ('completed','failed','cancelled')
31081
+ ORDER BY started_at DESC`).all(agentId).map((f) => ({
31082
+ id: f.id,
31083
+ state: f.state,
31084
+ summary: f.summary,
31085
+ startedAt: f.started_at
31086
+ }));
31087
+ const recentActivity = db().prepare(`SELECT ai.id, ai.kind, ai.ts, ai.title, ai.summary
31088
+ FROM activity_items ai
31089
+ WHERE ai.actor_id = ?
31090
+ ORDER BY ai.ts DESC
31091
+ LIMIT 20`).all(agentId).map((a) => ({
31092
+ id: a.id,
31093
+ kind: a.kind,
31094
+ ts: a.ts,
31095
+ title: a.title,
31096
+ summary: a.summary
31097
+ }));
31098
+ const msgRow = db().prepare(`SELECT COUNT(*) AS cnt FROM messages WHERE conversation_id = ?`).get(conversationIdForAgent(agentId));
31099
+ const messageCount = msgRow?.cnt ?? 0;
31100
+ const lastMessageAt = db().prepare(`SELECT MAX(created_at) AS last_at FROM messages WHERE actor_id = ?`).get(agentId)?.last_at ?? null;
31101
+ const isWorking = workingAgentIds.has(row.id);
31102
+ const state = isWorking ? "working" : row.state && row.state !== "offline" ? "available" : "offline";
31103
+ const statusLabel = isWorking ? "Working" : row.state === "active" ? "Available" : row.state ?? "Offline";
31104
+ return {
31105
+ id: row.id,
31106
+ title: row.display_name,
31107
+ selector: meta3.selector ?? null,
31108
+ defaultSelector: row.default_selector,
31109
+ workspaceRoot: compact(row.project_root),
31110
+ harness: row.harness,
31111
+ transport: row.transport,
31112
+ state,
31113
+ statusLabel: statusLabel.charAt(0).toUpperCase() + statusLabel.slice(1),
31114
+ sessionId: conversationIdForAgent(row.id),
31115
+ lastActiveAt: lastMessageAt,
31116
+ cwd: compact(row.cwd),
31117
+ wakePolicy: row.wake_policy,
31118
+ capabilities,
31119
+ branch: meta3.branch ?? null,
31120
+ role: meta3.role ?? null,
31121
+ model: meta3.model ?? null,
31122
+ activeFlights,
31123
+ recentActivity,
31124
+ messageCount
31125
+ };
31126
+ }
30947
31127
  var _db = null, HOME;
30948
31128
  var init_db_queries = __esm(() => {
30949
- HOME = homedir13();
31129
+ HOME = homedir14();
30950
31130
  });
30951
31131
 
30952
31132
  // ../../apps/desktop/src/core/pairing/runtime/bridge/router.ts
30953
- import { readFileSync as readFileSync10, readdirSync as readdirSync2, realpathSync as realpathSync2, statSync as statSync3 } from "fs";
31133
+ import { readFileSync as readFileSync11, readdirSync as readdirSync2, realpathSync as realpathSync2, statSync as statSync3 } from "fs";
30954
31134
  import { execSync as execSync3 } from "child_process";
30955
- import { basename as basename8, isAbsolute as isAbsolute4, join as join20, relative as relative3 } from "path";
30956
- import { homedir as homedir14 } from "os";
31135
+ import { basename as basename8, isAbsolute as isAbsolute4, join as join21, relative as relative3 } from "path";
31136
+ import { homedir as homedir15 } from "os";
30957
31137
  function resolveMobileCurrentDirectory2() {
30958
31138
  const config2 = resolveConfig();
30959
31139
  const configuredRoot = config2.workspace?.root;
@@ -30966,13 +31146,13 @@ function resolveMobileCurrentDirectory2() {
30966
31146
  }
30967
31147
  }
30968
31148
  function resolveWorkspaceRoot2(root) {
30969
- const expandedRoot = root.replace(/^~/, homedir14());
31149
+ const expandedRoot = root.replace(/^~/, homedir15());
30970
31150
  return realpathSync2(expandedRoot);
30971
31151
  }
30972
31152
  function resolveWorkspacePath2(root, requestedPath) {
30973
31153
  const normalizedRoot = resolveWorkspaceRoot2(root);
30974
- const expandedPath = requestedPath?.replace(/^~/, homedir14());
30975
- const candidate = expandedPath ? isAbsolute4(expandedPath) ? expandedPath : join20(normalizedRoot, expandedPath) : normalizedRoot;
31154
+ const expandedPath = requestedPath?.replace(/^~/, homedir15());
31155
+ const candidate = expandedPath ? isAbsolute4(expandedPath) ? expandedPath : join21(normalizedRoot, expandedPath) : normalizedRoot;
30976
31156
  const resolvedCandidate = realpathSync2(candidate);
30977
31157
  const rel = relative3(normalizedRoot, resolvedCandidate);
30978
31158
  if (rel === "" || !rel.startsWith("..") && !isAbsolute4(rel)) {
@@ -30987,7 +31167,7 @@ function listDirectories2(dirPath) {
30987
31167
  continue;
30988
31168
  if (name === "node_modules" || name === ".build" || name === "target")
30989
31169
  continue;
30990
- const fullPath = join20(dirPath, name);
31170
+ const fullPath = join21(dirPath, name);
30991
31171
  try {
30992
31172
  const stat4 = statSync3(fullPath);
30993
31173
  if (!stat4.isDirectory())
@@ -31026,7 +31206,7 @@ function detectAgent2(filePath) {
31026
31206
  return "unknown";
31027
31207
  }
31028
31208
  async function discoverSessionFiles2(maxAgeDays, limit) {
31029
- const home = homedir14();
31209
+ const home = homedir15();
31030
31210
  const results = [];
31031
31211
  const searchPaths = [
31032
31212
  { pattern: `${home}/.claude/projects`, agent: "claude-code" },
@@ -31154,9 +31334,12 @@ var init_router = __esm(async () => {
31154
31334
  init_dist2();
31155
31335
  init_zod();
31156
31336
  init_log();
31157
- init_config2();
31337
+ init_config3();
31158
31338
  init_db_queries();
31159
- await init_service5();
31339
+ await __promiseAll([
31340
+ init_service5(),
31341
+ init_local_agents()
31342
+ ]);
31160
31343
  t = initTRPC.context().create();
31161
31344
  logged = t.middleware(async ({ path: path2, type, next }) => {
31162
31345
  const start = Date.now();
@@ -31350,6 +31533,17 @@ var init_router = __esm(async () => {
31350
31533
  limit: exports_external.number().optional()
31351
31534
  }).optional()).query(async ({ input }) => {
31352
31535
  return getScoutMobileActivity(input);
31536
+ }),
31537
+ agentDetail: procedure.input(exports_external.object({ agentId: exports_external.string() })).query(async ({ input }) => {
31538
+ return queryMobileAgentDetail(input.agentId);
31539
+ }),
31540
+ agentRestart: procedure.input(exports_external.object({ agentId: exports_external.string() })).mutation(async ({ input }) => {
31541
+ const result = await restartLocalAgent(input.agentId);
31542
+ return { ok: result !== null, agentId: input.agentId };
31543
+ }),
31544
+ agentStop: procedure.input(exports_external.object({ agentId: exports_external.string() })).mutation(async ({ input }) => {
31545
+ const result = await stopLocalAgent(input.agentId);
31546
+ return { ok: result !== null, agentId: input.agentId };
31353
31547
  })
31354
31548
  });
31355
31549
  workspaceRouter = t.router({
@@ -31482,7 +31676,7 @@ var init_router = __esm(async () => {
31482
31676
  });
31483
31677
  }
31484
31678
  try {
31485
- const content = readFileSync10(input.path, "utf-8");
31679
+ const content = readFileSync11(input.path, "utf-8");
31486
31680
  const lines = content.split(`
31487
31681
  `).filter((l) => l.trim().length > 0);
31488
31682
  const trimmed = lines.length > 500 ? lines.slice(-500) : lines;
@@ -35608,14 +35802,14 @@ var init_observable = __esm(() => {
35608
35802
 
35609
35803
  // ../../apps/desktop/src/core/pairing/runtime/bridge/server-trpc.ts
35610
35804
  import { realpathSync as realpathSync3 } from "fs";
35611
- import { homedir as homedir15 } from "os";
35805
+ import { homedir as homedir16 } from "os";
35612
35806
  function resolveCurrentDirectory() {
35613
35807
  try {
35614
35808
  const config2 = resolveConfig();
35615
35809
  const configuredRoot = config2.workspace?.root;
35616
35810
  if (!configuredRoot)
35617
35811
  return process.cwd();
35618
- const expanded = configuredRoot.replace(/^~/, homedir15());
35812
+ const expanded = configuredRoot.replace(/^~/, homedir16());
35619
35813
  return realpathSync3(expanded);
35620
35814
  } catch {
35621
35815
  return process.cwd();
@@ -36022,7 +36216,7 @@ var init_server_trpc = __esm(async () => {
36022
36216
  init_rpc();
36023
36217
  init_observable();
36024
36218
  init_log();
36025
- init_config2();
36219
+ init_config3();
36026
36220
  init_security();
36027
36221
  await __promiseAll([
36028
36222
  init_server(),
@@ -36031,7 +36225,7 @@ var init_server_trpc = __esm(async () => {
36031
36225
  });
36032
36226
 
36033
36227
  // ../../apps/desktop/src/core/pairing/runtime/runtime.ts
36034
- import { homedir as homedir16 } from "os";
36228
+ import { homedir as homedir17 } from "os";
36035
36229
  function createPairingAdapterRegistry(configAdapters) {
36036
36230
  const adapters = {
36037
36231
  "claude-code": createAdapter,
@@ -36108,7 +36302,7 @@ async function autoStartConfiguredSessions(bridge, sessions3) {
36108
36302
  try {
36109
36303
  const session = await bridge.createSession(entry.adapter, {
36110
36304
  name: entry.name,
36111
- cwd: entry.cwd?.replace(/^~/, homedir16()),
36305
+ cwd: entry.cwd?.replace(/^~/, homedir17()),
36112
36306
  options: entry.options
36113
36307
  });
36114
36308
  console.log(`[bridge] session started: ${session.name} (${entry.adapter})`);
@@ -36125,7 +36319,7 @@ var init_runtime = __esm(async () => {
36125
36319
  init_opencode();
36126
36320
  init_pi();
36127
36321
  init_bridge();
36128
- init_config2();
36322
+ init_config3();
36129
36323
  init_fileserver();
36130
36324
  init_security2();
36131
36325
  await __promiseAll([
@@ -36135,10 +36329,10 @@ var init_runtime = __esm(async () => {
36135
36329
  });
36136
36330
 
36137
36331
  // ../../apps/desktop/src/core/pairing/runtime/log.ts
36138
- import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync7 } from "fs";
36332
+ import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync8 } from "fs";
36139
36333
  function write2(level, category, message, data) {
36140
36334
  const { rootDir, logPath } = pairingPaths();
36141
- mkdirSync7(rootDir, { recursive: true });
36335
+ mkdirSync8(rootDir, { recursive: true });
36142
36336
  const prefix = `${new Date().toISOString()} [${level.toUpperCase()}] [${category}]`;
36143
36337
  const line = data === undefined ? `${prefix} ${message}
36144
36338
  ` : `${prefix} ${message} ${JSON.stringify(data)}
@@ -36149,7 +36343,7 @@ function write2(level, category, message, data) {
36149
36343
  }
36150
36344
  var pairingLog;
36151
36345
  var init_log2 = __esm(() => {
36152
- init_config();
36346
+ init_config2();
36153
36347
  pairingLog = {
36154
36348
  debug: (category, message, data) => write2("debug", category, message, data),
36155
36349
  info: (category, message, data) => write2("info", category, message, data),
@@ -36383,11 +36577,11 @@ var BRIDGE_ABSENCE_GRACE_MS = 30000, ROOM_IDLE_TIMEOUT_MS = 60000;
36383
36577
 
36384
36578
  // ../../apps/desktop/src/core/pairing/runtime/relay-runtime.ts
36385
36579
  import { execSync as execSync4 } from "child_process";
36386
- import { existsSync as existsSync13, mkdirSync as mkdirSync8, readdirSync as readdirSync3 } from "fs";
36387
- import { homedir as homedir17 } from "os";
36388
- import { join as join21 } from "path";
36580
+ import { existsSync as existsSync14, mkdirSync as mkdirSync9, readdirSync as readdirSync3 } from "fs";
36581
+ import { homedir as homedir18 } from "os";
36582
+ import { join as join22 } from "path";
36389
36583
  function findStoredCerts() {
36390
- if (!existsSync13(PAIRING_DIR2)) {
36584
+ if (!existsSync14(PAIRING_DIR2)) {
36391
36585
  return null;
36392
36586
  }
36393
36587
  try {
@@ -36401,8 +36595,8 @@ function findStoredCerts() {
36401
36595
  return null;
36402
36596
  }
36403
36597
  return {
36404
- cert: join21(PAIRING_DIR2, certFile),
36405
- key: join21(PAIRING_DIR2, keyFile)
36598
+ cert: join22(PAIRING_DIR2, certFile),
36599
+ key: join22(PAIRING_DIR2, keyFile)
36406
36600
  };
36407
36601
  } catch {
36408
36602
  return null;
@@ -36422,9 +36616,9 @@ function getTailscaleHostname() {
36422
36616
  }
36423
36617
  }
36424
36618
  function generateTailscaleCerts(hostname5) {
36425
- mkdirSync8(PAIRING_DIR2, { recursive: true });
36426
- const certPath = join21(PAIRING_DIR2, `${hostname5}.crt`);
36427
- const keyPath = join21(PAIRING_DIR2, `${hostname5}.key`);
36619
+ mkdirSync9(PAIRING_DIR2, { recursive: true });
36620
+ const certPath = join22(PAIRING_DIR2, `${hostname5}.crt`);
36621
+ const keyPath = join22(PAIRING_DIR2, `${hostname5}.key`);
36428
36622
  try {
36429
36623
  pairingLog.info("relay", "generating tailscale TLS cert", { hostname: hostname5 });
36430
36624
  execSync4(`tailscale cert --cert-file "${certPath}" --key-file "${keyPath}" "${hostname5}"`, {
@@ -36439,9 +36633,9 @@ function generateTailscaleCerts(hostname5) {
36439
36633
  }
36440
36634
  }
36441
36635
  function generateSelfSignedCert(hostname5) {
36442
- mkdirSync8(PAIRING_DIR2, { recursive: true });
36443
- const certPath = join21(PAIRING_DIR2, `${hostname5}.crt`);
36444
- const keyPath = join21(PAIRING_DIR2, `${hostname5}.key`);
36636
+ mkdirSync9(PAIRING_DIR2, { recursive: true });
36637
+ const certPath = join22(PAIRING_DIR2, `${hostname5}.crt`);
36638
+ const keyPath = join22(PAIRING_DIR2, `${hostname5}.key`);
36445
36639
  try {
36446
36640
  execSync4(`openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 ` + `-keyout "${keyPath}" -out "${certPath}" -days 365 -nodes ` + `-subj "/CN=${hostname5}" -addext "subjectAltName=DNS:${hostname5}"`, {
36447
36641
  stdio: ["pipe", "pipe", "pipe"],
@@ -36504,7 +36698,7 @@ function startManagedRelay(port = 7889) {
36504
36698
  var PAIRING_DIR2;
36505
36699
  var init_relay_runtime = __esm(() => {
36506
36700
  init_log2();
36507
- PAIRING_DIR2 = join21(homedir17(), ".scout/pairing");
36701
+ PAIRING_DIR2 = join22(homedir18(), ".scout/pairing");
36508
36702
  });
36509
36703
 
36510
36704
  // ../../node_modules/.bun/uqr@0.1.3/node_modules/uqr/dist/index.mjs
@@ -37133,7 +37327,7 @@ var init_qr = __esm(() => {
37133
37327
 
37134
37328
  // ../../apps/desktop/src/core/pairing/runtime/index.ts
37135
37329
  var init_runtime2 = __esm(async () => {
37136
- init_config();
37330
+ init_config2();
37137
37331
  init_runtime_state();
37138
37332
  init_runtime();
37139
37333
  init_relay_runtime();
@@ -37475,8 +37669,8 @@ __export(exports_server, {
37475
37669
  renderServerCommandHelp: () => renderServerCommandHelp
37476
37670
  });
37477
37671
  import { spawn as spawn4 } from "child_process";
37478
- import { existsSync as existsSync14 } from "fs";
37479
- import { dirname as dirname9, join as join22 } from "path";
37672
+ import { existsSync as existsSync15 } from "fs";
37673
+ import { dirname as dirname10, join as join23 } from "path";
37480
37674
  import { fileURLToPath as fileURLToPath7 } from "url";
37481
37675
  function renderServerCommandHelp() {
37482
37676
  return [
@@ -37505,25 +37699,25 @@ function renderServerCommandHelp() {
37505
37699
  `);
37506
37700
  }
37507
37701
  function resolveScoutWebServerEntry() {
37508
- const mainDir = dirname9(fileURLToPath7(import.meta.url));
37509
- const bundled = join22(mainDir, "scout-web-server.mjs");
37510
- if (existsSync14(bundled)) {
37702
+ const mainDir = dirname10(fileURLToPath7(import.meta.url));
37703
+ const bundled = join23(mainDir, "scout-web-server.mjs");
37704
+ if (existsSync15(bundled)) {
37511
37705
  return bundled;
37512
37706
  }
37513
37707
  const source = fileURLToPath7(new URL("../../server/index.ts", import.meta.url));
37514
- if (existsSync14(source)) {
37708
+ if (existsSync15(source)) {
37515
37709
  return source;
37516
37710
  }
37517
37711
  throw new ScoutCliError("Could not find Scout web server entry. Rebuild @openscout/scout or run from the OpenScout repository.");
37518
37712
  }
37519
37713
  function resolveScoutControlPlaneWebServerEntry() {
37520
- const mainDir = dirname9(fileURLToPath7(import.meta.url));
37521
- const bundled = join22(mainDir, "scout-control-plane-web.mjs");
37522
- if (existsSync14(bundled)) {
37714
+ const mainDir = dirname10(fileURLToPath7(import.meta.url));
37715
+ const bundled = join23(mainDir, "scout-control-plane-web.mjs");
37716
+ if (existsSync15(bundled)) {
37523
37717
  return bundled;
37524
37718
  }
37525
37719
  const source = fileURLToPath7(new URL("../../server/control-plane-index.ts", import.meta.url));
37526
- if (existsSync14(source)) {
37720
+ if (existsSync15(source)) {
37527
37721
  return source;
37528
37722
  }
37529
37723
  throw new ScoutCliError("Could not find Scout control-plane web server entry. Rebuild @openscout/scout or run from the OpenScout repository.");
@@ -37569,10 +37763,10 @@ function parseServerStartFlags(args) {
37569
37763
  return { env };
37570
37764
  }
37571
37765
  function resolveBundledStaticClientRoot(entry, mode) {
37572
- const entryDir = dirname9(entry);
37573
- const clientDirectory = mode === "control-plane" ? join22(entryDir, "control-plane-client") : join22(entryDir, "client");
37574
- const indexPath = join22(clientDirectory, "index.html");
37575
- return existsSync14(indexPath) ? clientDirectory : null;
37766
+ const entryDir = dirname10(entry);
37767
+ const clientDirectory = mode === "control-plane" ? join23(entryDir, "control-plane-client") : join23(entryDir, "client");
37768
+ const indexPath = join23(clientDirectory, "index.html");
37769
+ return existsSync15(indexPath) ? clientDirectory : null;
37576
37770
  }
37577
37771
  async function runServerCommand(context, args) {
37578
37772
  if (args.length === 0 || args[0] === "help" || args[0] === "--help" || args[0] === "-h") {
@@ -37705,7 +37899,7 @@ var exports_up = {};
37705
37899
  __export(exports_up, {
37706
37900
  runUpCommand: () => runUpCommand
37707
37901
  });
37708
- import { existsSync as existsSync15 } from "fs";
37902
+ import { existsSync as existsSync16 } from "fs";
37709
37903
  import { resolve as resolve9 } from "path";
37710
37904
  function looksLikePath(value) {
37711
37905
  return value.includes("/") || value.startsWith(".") || value.startsWith("~");
@@ -37754,7 +37948,7 @@ async function runUpCommand(context, args) {
37754
37948
  throw new ScoutCliError("usage: scout up <name|path> [--name <alias>] [--harness <claude|codex>]");
37755
37949
  }
37756
37950
  let projectPath;
37757
- if (looksLikePath(target) || existsSync15(resolve9(target))) {
37951
+ if (looksLikePath(target) || existsSync16(resolve9(target))) {
37758
37952
  projectPath = resolve9(target);
37759
37953
  } else {
37760
37954
  const resolved = await resolveLocalAgentByName(target);
@@ -37880,6 +38074,8 @@ async function loadScoutCommandHandler(name) {
37880
38074
  return (await init_broadcast().then(() => exports_broadcast)).runBroadcastCommand;
37881
38075
  case "card":
37882
38076
  return (await init_card().then(() => exports_card)).runCardCommand;
38077
+ case "config":
38078
+ return (await Promise.resolve().then(() => (init_config(), exports_config))).runConfigCommand;
37883
38079
  case "down":
37884
38080
  return (await init_down().then(() => exports_down)).runDownCommand;
37885
38081
  case "doctor":
@@ -37935,6 +38131,7 @@ var SCOUT_COMMANDS = [
37935
38131
  { name: "down", summary: "Stop one or all local agents" },
37936
38132
  { name: "ps", summary: "List configured local agents" },
37937
38133
  { name: "restart", summary: "Restart configured local agents" },
38134
+ { name: "config", summary: "View or set user config (name, etc.)" },
37938
38135
  { name: "mesh", summary: "Mesh status and diagnostics" },
37939
38136
  { name: "pair", summary: "Pair a companion device via QR" },
37940
38137
  { name: "server", summary: "Run the Scout web UI (Bun; see: scout server start / control-plane start)" },
@@ -37995,7 +38192,7 @@ function renderScoutHelp(version2 = "0.2.18") {
37995
38192
  init_options();
37996
38193
 
37997
38194
  // ../../apps/desktop/src/shared/product.ts
37998
- var SCOUT_APP_VERSION = "0.2.23";
38195
+ var SCOUT_APP_VERSION = process.env.SCOUT_APP_VERSION?.trim() || "0.2.27";
37999
38196
 
38000
38197
  // ../../apps/desktop/src/cli/main.ts
38001
38198
  async function main2() {