@openscout/scout 0.2.19 → 0.2.21

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.
@@ -1998,6 +1998,7 @@ var init_user_project_hints = __esm(() => {
1998
1998
 
1999
1999
  // packages/runtime/src/setup.ts
2000
2000
  import { execFileSync as execFileSync2 } from "child_process";
2001
+ import { existsSync as existsSync3, readFileSync } from "fs";
2001
2002
  import { access, mkdir as mkdir2, readdir as readdir2, readFile as readFile3, realpath, rm, stat as stat2, writeFile as writeFile2 } from "fs/promises";
2002
2003
  import { homedir as homedir3, hostname, userInfo } from "os";
2003
2004
  import { basename, dirname as dirname3, isAbsolute, join as join4, relative, resolve as resolve2 } from "path";
@@ -2175,7 +2176,25 @@ function normalizeTelegramConversationId(value) {
2175
2176
  return normalized;
2176
2177
  }
2177
2178
  function resolveNodeQualifier() {
2178
- return normalizeAgentSelectorSegment(process.env.OPENSCOUT_NODE_QUALIFIER?.trim() || hostname() || "local") || "local";
2179
+ const fromEnv = process.env.OPENSCOUT_NODE_QUALIFIER?.trim();
2180
+ if (fromEnv) {
2181
+ return normalizeAgentSelectorSegment(fromEnv) || "local";
2182
+ }
2183
+ const alias = readNodeAliasSync();
2184
+ if (alias) {
2185
+ return normalizeAgentSelectorSegment(alias) || "local";
2186
+ }
2187
+ return normalizeAgentSelectorSegment(hostname() || "local") || "local";
2188
+ }
2189
+ function readNodeAliasSync() {
2190
+ try {
2191
+ const settingsPath = resolveOpenScoutSupportPaths().settingsPath;
2192
+ const raw2 = readFileSync(settingsPath, "utf8");
2193
+ const settings = JSON.parse(raw2);
2194
+ return settings.node?.alias?.trim() || null;
2195
+ } catch {
2196
+ return null;
2197
+ }
2179
2198
  }
2180
2199
  function detectGitBranchUncached(projectRoot) {
2181
2200
  try {
@@ -2376,6 +2395,9 @@ function defaultSettings() {
2376
2395
  completedAt: null,
2377
2396
  skippedAt: null
2378
2397
  },
2398
+ node: {
2399
+ alias: ""
2400
+ },
2379
2401
  discovery: {
2380
2402
  contextRoot: null,
2381
2403
  workspaceRoots: [],
@@ -2775,6 +2797,7 @@ async function normalizeSettingsRecord(value, options = {}) {
2775
2797
  const candidate = typeof value === "object" && value ? value : {};
2776
2798
  const profile = typeof candidate.profile === "object" && candidate.profile ? candidate.profile : {};
2777
2799
  const onboarding = typeof candidate.onboarding === "object" && candidate.onboarding ? candidate.onboarding : {};
2800
+ const node = typeof candidate.node === "object" && candidate.node ? candidate.node : {};
2778
2801
  const discovery = typeof candidate.discovery === "object" && candidate.discovery ? candidate.discovery : {};
2779
2802
  const agents = typeof candidate.agents === "object" && candidate.agents ? candidate.agents : {};
2780
2803
  const bridges = typeof candidate.bridges === "object" && candidate.bridges ? candidate.bridges : {};
@@ -2814,6 +2837,9 @@ async function normalizeSettingsRecord(value, options = {}) {
2814
2837
  completedAt: normalizeOptionalTimestamp(onboarding.completedAt),
2815
2838
  skippedAt: normalizeOptionalTimestamp(onboarding.skippedAt)
2816
2839
  },
2840
+ node: {
2841
+ alias: normalizeOptionalString(node.alias)
2842
+ },
2817
2843
  discovery: {
2818
2844
  contextRoot,
2819
2845
  workspaceRoots,
@@ -2891,6 +2917,10 @@ async function writeOpenScoutSettings(settings, options = {}) {
2891
2917
  ...current.onboarding,
2892
2918
  ...settings.onboarding ?? {}
2893
2919
  },
2920
+ node: {
2921
+ ...current.node,
2922
+ ...settings.node ?? {}
2923
+ },
2894
2924
  discovery: {
2895
2925
  ...current.discovery,
2896
2926
  ...settings.discovery ?? {},
@@ -3822,6 +3852,9 @@ function resolveClaudeStreamJsonOutput(result, fallbackParts) {
3822
3852
  function sessionKey(options) {
3823
3853
  return `${options.agentName}:${options.sessionId}`;
3824
3854
  }
3855
+ function errorMessage(error) {
3856
+ return error instanceof Error ? error.message : String(error);
3857
+ }
3825
3858
  async function readOptionalFile(filePath) {
3826
3859
  try {
3827
3860
  const raw2 = await readFile4(filePath, "utf8");
@@ -3974,17 +4007,35 @@ class ClaudeStreamJsonSession {
3974
4007
  if (this.claudeSessionId) {
3975
4008
  args.push("--resume", this.claudeSessionId);
3976
4009
  }
3977
- this.process = spawn2("claude", args, {
3978
- cwd: this.options.cwd,
3979
- env: buildManagedAgentEnvironment({
3980
- agentName: this.options.agentName,
3981
- currentDirectory: this.options.cwd,
3982
- baseEnv: process.env
3983
- })
4010
+ let child;
4011
+ try {
4012
+ child = spawn2("claude", args, {
4013
+ cwd: this.options.cwd,
4014
+ env: buildManagedAgentEnvironment({
4015
+ agentName: this.options.agentName,
4016
+ currentDirectory: this.options.cwd,
4017
+ baseEnv: process.env
4018
+ })
4019
+ });
4020
+ } catch (error) {
4021
+ throw new Error(`Failed to spawn claude: ${errorMessage(error)}`);
4022
+ }
4023
+ this.process = child;
4024
+ child.on("error", (error) => {
4025
+ console.error(`[openscout-runtime] claude process error for ${this.options.agentName}: ${error.message}`);
4026
+ this.process = null;
4027
+ if (this.activeTurn) {
4028
+ const turn = this.activeTurn;
4029
+ this.activeTurn = null;
4030
+ if (turn.timer) {
4031
+ clearTimeout(turn.timer);
4032
+ }
4033
+ turn.reject(new Error(`Claude process error: ${error.message}`));
4034
+ }
3984
4035
  });
3985
- this.process.stdout.setEncoding("utf8");
3986
- this.process.stderr.setEncoding("utf8");
3987
- this.process.stdout.on("data", (chunk) => {
4036
+ child.stdout.setEncoding("utf8");
4037
+ child.stderr.setEncoding("utf8");
4038
+ child.stdout.on("data", (chunk) => {
3988
4039
  appendFile(this.stdoutLogPath, chunk).catch(() => {
3989
4040
  return;
3990
4041
  });
@@ -4000,12 +4051,12 @@ class ClaudeStreamJsonSession {
4000
4051
  this.handleEvent(JSON.parse(trimmed));
4001
4052
  }
4002
4053
  });
4003
- this.process.stderr.on("data", (chunk) => {
4054
+ child.stderr.on("data", (chunk) => {
4004
4055
  appendFile(this.stderrLogPath, chunk).catch(() => {
4005
4056
  return;
4006
4057
  });
4007
4058
  });
4008
- this.process.on("exit", (code) => {
4059
+ child.on("exit", (code) => {
4009
4060
  if (code !== 0 && this.activeTurn) {
4010
4061
  const turn = this.activeTurn;
4011
4062
  this.activeTurn = null;
@@ -4150,7 +4201,7 @@ function parseJsonLine(line) {
4150
4201
  return null;
4151
4202
  }
4152
4203
  }
4153
- function errorMessage(error) {
4204
+ function errorMessage2(error) {
4154
4205
  if (error instanceof Error) {
4155
4206
  return error.message;
4156
4207
  }
@@ -4175,7 +4226,7 @@ async function readOptionalFile2(filePath) {
4175
4226
  }
4176
4227
  }
4177
4228
  function isMissingCodexRolloutError(error) {
4178
- const message = errorMessage(error).toLowerCase();
4229
+ const message = errorMessage2(error).toLowerCase();
4179
4230
  return message.includes("no rollout found for thread id");
4180
4231
  }
4181
4232
 
@@ -4248,7 +4299,7 @@ class CodexAppServerSession {
4248
4299
  await this.persistState();
4249
4300
  } catch (error) {
4250
4301
  this.clearActiveTurn(turn);
4251
- reject(error instanceof Error ? error : new Error(errorMessage(error)));
4302
+ reject(error instanceof Error ? error : new Error(errorMessage2(error)));
4252
4303
  }
4253
4304
  });
4254
4305
  return {
@@ -4376,7 +4427,7 @@ class CodexAppServerSession {
4376
4427
  });
4377
4428
  });
4378
4429
  child.once("error", (error) => {
4379
- this.failSession(new Error(`Codex app-server failed for ${this.options.agentName}: ${errorMessage(error)}`));
4430
+ this.failSession(new Error(`Codex app-server failed for ${this.options.agentName}: ${errorMessage2(error)}`));
4380
4431
  });
4381
4432
  child.once("exit", (code, signal) => {
4382
4433
  this.failSession(new Error(`Codex app-server exited for ${this.options.agentName}` + (code !== null ? ` with code ${code}` : "") + (signal ? ` (${signal})` : "")));
@@ -4412,7 +4463,7 @@ class CodexAppServerSession {
4412
4463
  await this.persistThreadId();
4413
4464
  return;
4414
4465
  } catch (error) {
4415
- await appendFile2(this.stderrLogPath, `[openscout] failed to resume stored Codex thread ${storedThreadId}: ${errorMessage(error)}
4466
+ await appendFile2(this.stderrLogPath, `[openscout] failed to resume stored Codex thread ${storedThreadId}: ${errorMessage2(error)}
4416
4467
  `).catch(() => {
4417
4468
  return;
4418
4469
  });
@@ -4682,7 +4733,7 @@ class CodexAppServerSession {
4682
4733
  });
4683
4734
  } catch (error) {
4684
4735
  this.pendingRequests.delete(id);
4685
- reject(error instanceof Error ? error : new Error(errorMessage(error)));
4736
+ reject(error instanceof Error ? error : new Error(errorMessage2(error)));
4686
4737
  }
4687
4738
  });
4688
4739
  }
@@ -4759,7 +4810,7 @@ function buildCollaborationContractPrompt(agentId) {
4759
4810
 
4760
4811
  // packages/runtime/src/broker-service.ts
4761
4812
  import { spawnSync } from "child_process";
4762
- import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
4813
+ import { existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync2, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
4763
4814
  import { homedir as homedir5 } from "os";
4764
4815
  import { basename as basename3, dirname as dirname5, join as join8, resolve as resolve3 } from "path";
4765
4816
  import { fileURLToPath as fileURLToPath4 } from "url";
@@ -4780,7 +4831,7 @@ function runtimePackageDir() {
4780
4831
  return resolve3(moduleDir, "..");
4781
4832
  }
4782
4833
  function isInstalledRuntimePackageDir(candidate) {
4783
- return existsSync4(join8(candidate, "package.json")) && existsSync4(join8(candidate, "bin", "openscout-runtime.mjs"));
4834
+ return existsSync5(join8(candidate, "package.json")) && existsSync5(join8(candidate, "bin", "openscout-runtime.mjs"));
4784
4835
  }
4785
4836
  function findGlobalRuntimeDir() {
4786
4837
  const bunCandidate = join8(homedir5(), ".bun", "node_modules", "@openscout", "runtime");
@@ -4798,7 +4849,7 @@ function findWorkspaceRuntimeDir(startDir) {
4798
4849
  let current = resolve3(startDir);
4799
4850
  while (true) {
4800
4851
  const candidate = join8(current, "packages", "runtime");
4801
- if (existsSync4(join8(candidate, "package.json")) && existsSync4(join8(candidate, "src"))) {
4852
+ if (existsSync5(join8(candidate, "package.json")) && existsSync5(join8(candidate, "src"))) {
4802
4853
  return candidate;
4803
4854
  }
4804
4855
  const parent = dirname5(current);
@@ -4812,18 +4863,18 @@ function resolveBunExecutable() {
4812
4863
  if (explicit && explicit.trim().length > 0) {
4813
4864
  return explicit;
4814
4865
  }
4815
- if (basename3(process.execPath).startsWith("bun") && existsSync4(process.execPath)) {
4866
+ if (basename3(process.execPath).startsWith("bun") && existsSync5(process.execPath)) {
4816
4867
  return process.execPath;
4817
4868
  }
4818
4869
  const pathEntries = (process.env.PATH ?? "").split(":").filter(Boolean);
4819
4870
  for (const entry of pathEntries) {
4820
4871
  const candidate = join8(entry, "bun");
4821
- if (existsSync4(candidate)) {
4872
+ if (existsSync5(candidate)) {
4822
4873
  return candidate;
4823
4874
  }
4824
4875
  }
4825
4876
  const homeBun = join8(homedir5(), ".bun", "bin", "bun");
4826
- if (existsSync4(homeBun)) {
4877
+ if (existsSync5(homeBun)) {
4827
4878
  return homeBun;
4828
4879
  }
4829
4880
  return "bun";
@@ -5009,10 +5060,10 @@ function launchctlPath() {
5009
5060
  return "/bin/launchctl";
5010
5061
  }
5011
5062
  function readLogLines(path) {
5012
- if (!existsSync4(path)) {
5063
+ if (!existsSync5(path)) {
5013
5064
  return [];
5014
5065
  }
5015
- return readFileSync(path, "utf8").split(`
5066
+ return readFileSync2(path, "utf8").split(`
5016
5067
  `).map((line) => line.trim()).filter(Boolean);
5017
5068
  }
5018
5069
  function isPackageScriptBanner(line) {
@@ -5109,7 +5160,7 @@ async function brokerServiceStatus(config = resolveBrokerServiceConfig()) {
5109
5160
  ensureServiceDirectories(config);
5110
5161
  const launchctl = inspectLaunchctl(config);
5111
5162
  const health = await fetchHealthSnapshot(config);
5112
- const installed = existsSync4(config.launchAgentPath);
5163
+ const installed = existsSync5(config.launchAgentPath);
5113
5164
  const lastLogLine = health.reachable ? readLastLogLine([config.stdoutLogPath, config.stderrLogPath]) : readLastLogLine([config.stderrLogPath, config.stdoutLogPath]);
5114
5165
  return {
5115
5166
  label: config.label,
@@ -5171,7 +5222,7 @@ async function restartBrokerService(config = resolveBrokerServiceConfig()) {
5171
5222
  }
5172
5223
  async function uninstallBrokerService(config = resolveBrokerServiceConfig()) {
5173
5224
  await stopBrokerService(config);
5174
- if (existsSync4(config.launchAgentPath)) {
5225
+ if (existsSync5(config.launchAgentPath)) {
5175
5226
  rmSync2(config.launchAgentPath, { force: true });
5176
5227
  }
5177
5228
  return brokerServiceStatus(config);
@@ -5250,7 +5301,7 @@ var init_local_agent_template = __esm(() => {
5250
5301
 
5251
5302
  // packages/runtime/src/local-agents.ts
5252
5303
  import { execFileSync as execFileSync3, execSync } from "child_process";
5253
- import { existsSync as existsSync5, readFileSync as readFileSync2 } from "fs";
5304
+ import { existsSync as existsSync6, readFileSync as readFileSync3 } from "fs";
5254
5305
  import { mkdir as mkdir5, rm as rm4, stat as stat3, writeFile as writeFile5 } from "fs/promises";
5255
5306
  import { basename as basename4, dirname as dirname6, join as join9, resolve as resolve4 } from "path";
5256
5307
  import { fileURLToPath as fileURLToPath5 } from "url";
@@ -5263,10 +5314,10 @@ function resolveProjectsRoot(projectPath) {
5263
5314
  }
5264
5315
  try {
5265
5316
  const supportPaths = resolveOpenScoutSupportPaths();
5266
- if (!existsSync5(supportPaths.settingsPath)) {
5317
+ if (!existsSync6(supportPaths.settingsPath)) {
5267
5318
  return dirname6(projectPath);
5268
5319
  }
5269
- const raw2 = JSON.parse(readFileSync2(supportPaths.settingsPath, "utf8"));
5320
+ const raw2 = JSON.parse(readFileSync3(supportPaths.settingsPath, "utf8"));
5270
5321
  const workspaceRoot = raw2.discovery?.workspaceRoots?.find((entry) => typeof entry === "string" && entry.trim().length > 0);
5271
5322
  return workspaceRoot ? resolve4(workspaceRoot) : dirname6(projectPath);
5272
5323
  } catch {
@@ -5293,7 +5344,7 @@ function resolveScoutSkillPath() {
5293
5344
  join9(process.env.HOME ?? "", ".agents", "skills", "relay-agent-comms", "SKILL.md")
5294
5345
  ];
5295
5346
  for (const path of candidatePaths) {
5296
- if (existsSync5(path)) {
5347
+ if (existsSync6(path)) {
5297
5348
  return path;
5298
5349
  }
5299
5350
  }
@@ -5925,11 +5976,33 @@ function killAgentSession(sessionName) {
5925
5976
  execSync(`tmux kill-session -t ${JSON.stringify(sessionName)}`, { stdio: "pipe" });
5926
5977
  } catch {}
5927
5978
  }
5979
+ function isHarnessBinaryAvailable(transport) {
5980
+ const binaryMap = {
5981
+ claude_stream_json: "claude",
5982
+ codex_app_server: "codex"
5983
+ };
5984
+ const binary = binaryMap[transport];
5985
+ if (!binary)
5986
+ return true;
5987
+ try {
5988
+ execFileSync3("sh", ["-lc", `command -v ${binary}`], {
5989
+ stdio: ["ignore", "pipe", "ignore"],
5990
+ encoding: "utf8"
5991
+ });
5992
+ return true;
5993
+ } catch {
5994
+ return false;
5995
+ }
5996
+ }
5928
5997
  async function ensureLocalAgentOnline(agentName, record) {
5929
5998
  const normalizedRecord = normalizeLocalAgentRecord(agentName, record);
5930
5999
  if (isLocalAgentRecordOnline(agentName, normalizedRecord)) {
5931
6000
  return normalizedRecord;
5932
6001
  }
6002
+ if (!isHarnessBinaryAvailable(normalizedRecord.transport)) {
6003
+ console.warn(`[openscout-runtime] skipping warmup for ${agentName}: harness binary for ${normalizedRecord.transport} not found in PATH`);
6004
+ return normalizedRecord;
6005
+ }
5933
6006
  const projectPath = normalizedRecord.cwd;
5934
6007
  const projectName = normalizedRecord.project || basename4(projectPath);
5935
6008
  const systemPromptTemplate = normalizedRecord.systemPrompt || buildLocalAgentSystemPromptTemplate();
@@ -6039,7 +6112,7 @@ async function ensureLocalAgentOnline(agentName, record) {
6039
6112
  await new Promise((resolve5) => setTimeout(resolve5, 100));
6040
6113
  }
6041
6114
  if (!isLocalAgentSessionAlive(normalizedRecord.tmuxSession)) {
6042
- const stderrTail = existsSync5(stderrLogFile) ? readFileSync2(stderrLogFile, "utf8").trim().split(/\r?\n/).slice(-10).join(`
6115
+ const stderrTail = existsSync6(stderrLogFile) ? readFileSync3(stderrLogFile, "utf8").trim().split(/\r?\n/).slice(-10).join(`
6043
6116
  `).trim() : "";
6044
6117
  throw new Error(stderrTail ? `Relay agent ${agentName} failed to stay online:
6045
6118
  ${stderrTail}` : `Relay agent ${agentName} failed to stay online.`);
@@ -6320,15 +6393,26 @@ async function loadRegisteredLocalAgentBindings(nodeId, options = {}) {
6320
6393
  ]);
6321
6394
  const requestedAgentIds = new Set((options.agentIds ?? []).filter(Boolean));
6322
6395
  const selectedEntries = Object.entries(registry).filter(([agentId]) => requestedAgentIds.size === 0 || requestedAgentIds.has(agentId));
6323
- return Promise.all(selectedEntries.map(async ([agentId, record]) => {
6396
+ const results = await Promise.all(selectedEntries.map(async ([agentId, record]) => {
6324
6397
  const baseRecord = overrides[agentId]?.projectRoot ? {
6325
6398
  ...record,
6326
6399
  projectRoot: overrides[agentId].projectRoot
6327
6400
  } : record;
6328
6401
  const harnessRecord = options.harness ? recordForHarness(baseRecord, options.harness) : baseRecord;
6329
- const effectiveRecord = options.ensureOnline ? await ensureLocalAgentOnline(agentId, harnessRecord) : normalizeLocalAgentRecord(agentId, harnessRecord);
6402
+ let effectiveRecord;
6403
+ if (options.ensureOnline) {
6404
+ try {
6405
+ effectiveRecord = await ensureLocalAgentOnline(agentId, harnessRecord);
6406
+ } catch (error) {
6407
+ console.error(`[openscout-runtime] failed to warm agent ${agentId}: ${error instanceof Error ? error.message : error}`);
6408
+ effectiveRecord = normalizeLocalAgentRecord(agentId, harnessRecord);
6409
+ }
6410
+ } else {
6411
+ effectiveRecord = normalizeLocalAgentRecord(agentId, harnessRecord);
6412
+ }
6330
6413
  return buildLocalAgentBinding(agentId, effectiveRecord, isLocalAgentRecordOnline(agentId, effectiveRecord), nodeId, "relay-agent-registry");
6331
6414
  }));
6415
+ return results;
6332
6416
  }
6333
6417
  async function inferLocalAgentBinding(agentId, nodeId) {
6334
6418
  if (!agentId || BUILT_IN_LOCAL_AGENT_IDS.has(agentId)) {
@@ -7940,7 +8024,7 @@ init_setup();
7940
8024
 
7941
8025
  // apps/desktop/src/shared/product.ts
7942
8026
  var SCOUT_PRODUCT_NAME = "Scout";
7943
- var SCOUT_APP_VERSION = "0.2.19";
8027
+ var SCOUT_APP_VERSION = "0.2.21";
7944
8028
 
7945
8029
  // apps/desktop/src/shared/surface-capabilities.ts
7946
8030
  function resolveScoutSurfaceCapabilities(surface) {
@@ -7987,7 +8071,7 @@ import path3 from "path";
7987
8071
  // apps/desktop/src/app/host/runtime-service-client.ts
7988
8072
  import { spawn } from "child_process";
7989
8073
  import { basename as basename2, dirname as dirname4, join as join5 } from "path";
7990
- import { existsSync as existsSync3 } from "fs";
8074
+ import { existsSync as existsSync4 } from "fs";
7991
8075
  import { fileURLToPath as fileURLToPath3 } from "url";
7992
8076
  import { homedir as homedir4 } from "os";
7993
8077
  function tryWhich(executableName) {
@@ -7997,13 +8081,13 @@ function tryWhich(executableName) {
7997
8081
  if (!dir)
7998
8082
  continue;
7999
8083
  const candidate = join5(dir, executableName);
8000
- if (existsSync3(candidate)) {
8084
+ if (existsSync4(candidate)) {
8001
8085
  return candidate;
8002
8086
  }
8003
8087
  if (process.platform === "win32") {
8004
8088
  for (const ext of [".cmd", ".exe", ".bat"]) {
8005
8089
  const withExt = candidate + ext;
8006
- if (existsSync3(withExt))
8090
+ if (existsSync4(withExt))
8007
8091
  return withExt;
8008
8092
  }
8009
8093
  }
@@ -8015,7 +8099,7 @@ function findNodeModulesRuntimeBin() {
8015
8099
  let dir = dirname4(fileURLToPath3(import.meta.url));
8016
8100
  for (let i = 0;i < 24; i++) {
8017
8101
  const candidate = join5(dir, runtimeBinRel);
8018
- if (existsSync3(candidate))
8102
+ if (existsSync4(candidate))
8019
8103
  return candidate;
8020
8104
  const parent = dirname4(dir);
8021
8105
  if (parent === dir)
@@ -8023,7 +8107,7 @@ function findNodeModulesRuntimeBin() {
8023
8107
  dir = parent;
8024
8108
  }
8025
8109
  const bunGlobal = join5(homedir4(), ".bun", "install", "global", "node_modules", "@openscout", "runtime", "bin", "openscout-runtime.mjs");
8026
- if (existsSync3(bunGlobal))
8110
+ if (existsSync4(bunGlobal))
8027
8111
  return bunGlobal;
8028
8112
  return null;
8029
8113
  }
@@ -8031,7 +8115,7 @@ function findMonorepoOpenscoutRuntimeBin() {
8031
8115
  let dir = process.cwd();
8032
8116
  for (let i = 0;i < 24; i++) {
8033
8117
  const candidate = join5(dir, "packages", "runtime", "bin", "openscout-runtime.mjs");
8034
- if (existsSync3(candidate)) {
8118
+ if (existsSync4(candidate)) {
8035
8119
  return candidate;
8036
8120
  }
8037
8121
  const parent = dirname4(dir);
@@ -8044,7 +8128,7 @@ function findMonorepoOpenscoutRuntimeBin() {
8044
8128
  function resolveJavaScriptRuntimeExecutable() {
8045
8129
  const explicit = process.env.OPENSCOUT_RUNTIME_NODE_BIN?.trim();
8046
8130
  if (explicit) {
8047
- if (existsSync3(explicit)) {
8131
+ if (existsSync4(explicit)) {
8048
8132
  return explicit;
8049
8133
  }
8050
8134
  const found = tryWhich(explicit);
@@ -8070,7 +8154,7 @@ function resolveJavaScriptRuntimeExecutable() {
8070
8154
  function resolveRuntimeServiceEntrypoint() {
8071
8155
  const explicit = process.env.OPENSCOUT_RUNTIME_BIN?.trim();
8072
8156
  if (explicit) {
8073
- if (existsSync3(explicit)) {
8157
+ if (existsSync4(explicit)) {
8074
8158
  return explicit;
8075
8159
  }
8076
8160
  const found = tryWhich(explicit);
@@ -8662,7 +8746,7 @@ function createScoutVoiceState(input = {}) {
8662
8746
  // apps/desktop/src/app/desktop/shell-probes.ts
8663
8747
  init_setup();
8664
8748
  init_support_paths();
8665
- import { existsSync as existsSync6, readFileSync as readFileSync3 } from "fs";
8749
+ import { existsSync as existsSync7, readFileSync as readFileSync4 } from "fs";
8666
8750
  import path2 from "path";
8667
8751
 
8668
8752
  // apps/desktop/src/app/desktop/shell-utils.ts
@@ -8747,7 +8831,7 @@ var PROJECT_GIT_ACTIVITY_CACHE_TTL_MS = 60000;
8747
8831
  var projectGitActivityCache = new Map;
8748
8832
  function readHelperStatus() {
8749
8833
  const statusPath = resolveOpenScoutSupportPaths().desktopStatusPath;
8750
- if (!existsSync6(statusPath)) {
8834
+ if (!existsSync7(statusPath)) {
8751
8835
  return {
8752
8836
  running: false,
8753
8837
  detail: null,
@@ -8755,7 +8839,7 @@ function readHelperStatus() {
8755
8839
  };
8756
8840
  }
8757
8841
  try {
8758
- const raw2 = JSON.parse(readFileSync3(statusPath, "utf8"));
8842
+ const raw2 = JSON.parse(readFileSync4(statusPath, "utf8"));
8759
8843
  return {
8760
8844
  running: raw2.state === "running",
8761
8845
  detail: typeof raw2.detail === "string" ? raw2.detail : null,
@@ -8793,7 +8877,7 @@ function readTmuxSessionOutput() {
8793
8877
  }
8794
8878
  function readDesktopSettingsRecord() {
8795
8879
  try {
8796
- return JSON.parse(readFileSync3(resolveOpenScoutSupportPaths().settingsPath, "utf8"));
8880
+ return JSON.parse(readFileSync4(resolveOpenScoutSupportPaths().settingsPath, "utf8"));
8797
8881
  } catch {
8798
8882
  return {};
8799
8883
  }
@@ -11648,22 +11732,22 @@ async function sendScoutElectronRelayMessage(input, options = {}) {
11648
11732
  init_support_paths();
11649
11733
  import { execFileSync as execFileSync5 } from "child_process";
11650
11734
  import { randomUUID as randomUUID2 } from "crypto";
11651
- import { existsSync as existsSync10, readFileSync as readFileSync6 } from "fs";
11735
+ import { existsSync as existsSync11, readFileSync as readFileSync7 } from "fs";
11652
11736
  import { open as open2 } from "fs/promises";
11653
11737
  import os from "os";
11654
11738
  import path5 from "path";
11655
11739
 
11656
11740
  // apps/desktop/src/shared/paths.ts
11657
- import { existsSync as existsSync7, readFileSync as readFileSync4 } from "fs";
11741
+ import { existsSync as existsSync8, readFileSync as readFileSync5 } from "fs";
11658
11742
  import { dirname as dirname7, join as join10, resolve as resolve5 } from "path";
11659
11743
  import { fileURLToPath as fileURLToPath6 } from "url";
11660
11744
  function looksLikeWorkspaceRoot(candidate) {
11661
11745
  const packageJsonPath = join10(candidate, "package.json");
11662
- if (!existsSync7(packageJsonPath)) {
11746
+ if (!existsSync8(packageJsonPath)) {
11663
11747
  return false;
11664
11748
  }
11665
11749
  try {
11666
- const parsed = JSON.parse(readFileSync4(packageJsonPath, "utf8"));
11750
+ const parsed = JSON.parse(readFileSync5(packageJsonPath, "utf8"));
11667
11751
  return Array.isArray(parsed.workspaces);
11668
11752
  } catch {
11669
11753
  return false;
@@ -11671,11 +11755,11 @@ function looksLikeWorkspaceRoot(candidate) {
11671
11755
  }
11672
11756
  function looksLikePackagedAppRoot(candidate) {
11673
11757
  const packageJsonPath = join10(candidate, "package.json");
11674
- if (!existsSync7(packageJsonPath)) {
11758
+ if (!existsSync8(packageJsonPath)) {
11675
11759
  return false;
11676
11760
  }
11677
11761
  try {
11678
- const parsed = JSON.parse(readFileSync4(packageJsonPath, "utf8"));
11762
+ const parsed = JSON.parse(readFileSync5(packageJsonPath, "utf8"));
11679
11763
  return parsed.name === "@scout/electron-app";
11680
11764
  } catch {
11681
11765
  return false;
@@ -11683,18 +11767,18 @@ function looksLikePackagedAppRoot(candidate) {
11683
11767
  }
11684
11768
  function looksLikeInstalledCliRoot(candidate) {
11685
11769
  const packageJsonPath = join10(candidate, "package.json");
11686
- if (!existsSync7(packageJsonPath)) {
11770
+ if (!existsSync8(packageJsonPath)) {
11687
11771
  return false;
11688
11772
  }
11689
11773
  try {
11690
- const parsed = JSON.parse(readFileSync4(packageJsonPath, "utf8"));
11774
+ const parsed = JSON.parse(readFileSync5(packageJsonPath, "utf8"));
11691
11775
  return parsed.name === "@openscout/scout" || parsed.name === "@openscout/cli";
11692
11776
  } catch {
11693
11777
  return false;
11694
11778
  }
11695
11779
  }
11696
11780
  function looksLikeSourceAppRoot(candidate) {
11697
- return existsSync7(join10(candidate, "bin", "scout.ts"));
11781
+ return existsSync8(join10(candidate, "bin", "scout.ts"));
11698
11782
  }
11699
11783
  function findMatchingAncestor(startDirectory, predicate) {
11700
11784
  let current = resolve5(startDirectory);
@@ -11768,9 +11852,9 @@ import { spawn as spawn4 } from "child_process";
11768
11852
  import {
11769
11853
  accessSync,
11770
11854
  constants as constants2,
11771
- existsSync as existsSync8,
11855
+ existsSync as existsSync9,
11772
11856
  mkdirSync as mkdirSync3,
11773
- readFileSync as readFileSync5,
11857
+ readFileSync as readFileSync6,
11774
11858
  statSync as statSync2,
11775
11859
  unlinkSync,
11776
11860
  writeFileSync as writeFileSync3
@@ -12009,11 +12093,11 @@ async function loadScoutPairingPendingApprovals(port) {
12009
12093
  }
12010
12094
  function loadScoutPairingConfig() {
12011
12095
  const { configPath } = resolveScoutPairingPaths();
12012
- if (!existsSync8(configPath)) {
12096
+ if (!existsSync9(configPath)) {
12013
12097
  return {};
12014
12098
  }
12015
12099
  try {
12016
- const payload = JSON.parse(readFileSync5(configPath, "utf8"));
12100
+ const payload = JSON.parse(readFileSync6(configPath, "utf8"));
12017
12101
  return typeof payload === "object" && payload ? payload : {};
12018
12102
  } catch {
12019
12103
  return {};
@@ -12044,11 +12128,11 @@ async function resolveDefaultScoutPairingWorkspaceRoot(currentDirectory) {
12044
12128
  }
12045
12129
  function readScoutPairingRuntimeSnapshot() {
12046
12130
  const { runtimeStatePath } = resolveScoutPairingPaths();
12047
- if (!existsSync8(runtimeStatePath)) {
12131
+ if (!existsSync9(runtimeStatePath)) {
12048
12132
  return null;
12049
12133
  }
12050
12134
  try {
12051
- const parsed = JSON.parse(readFileSync5(runtimeStatePath, "utf8"));
12135
+ const parsed = JSON.parse(readFileSync6(runtimeStatePath, "utf8"));
12052
12136
  return parsed?.version === SCOUT_PAIRING_RUNTIME_VERSION ? parsed : null;
12053
12137
  } catch {
12054
12138
  return null;
@@ -12062,11 +12146,11 @@ function clearScoutPairingRuntimeSnapshot() {
12062
12146
  }
12063
12147
  function readScoutPairingRuntimePid() {
12064
12148
  const { runtimePidPath } = resolveScoutPairingPaths();
12065
- if (!existsSync8(runtimePidPath)) {
12149
+ if (!existsSync9(runtimePidPath)) {
12066
12150
  return null;
12067
12151
  }
12068
12152
  try {
12069
- const raw2 = readFileSync5(runtimePidPath, "utf8").trim();
12153
+ const raw2 = readFileSync6(runtimePidPath, "utf8").trim();
12070
12154
  const pid = Number(raw2);
12071
12155
  return Number.isInteger(pid) && pid > 0 ? pid : null;
12072
12156
  } catch {
@@ -12118,22 +12202,22 @@ function clearStaleScoutPairingRuntimeFiles() {
12118
12202
  clearScoutPairingRuntimeSnapshot();
12119
12203
  }
12120
12204
  function readScoutPairingIdentityFingerprint(identityPath) {
12121
- if (!existsSync8(identityPath)) {
12205
+ if (!existsSync9(identityPath)) {
12122
12206
  return null;
12123
12207
  }
12124
12208
  try {
12125
- const payload = JSON.parse(readFileSync5(identityPath, "utf8"));
12209
+ const payload = JSON.parse(readFileSync6(identityPath, "utf8"));
12126
12210
  return typeof payload.publicKey === "string" && payload.publicKey.length > 0 ? payload.publicKey.slice(0, 16) : null;
12127
12211
  } catch {
12128
12212
  return null;
12129
12213
  }
12130
12214
  }
12131
12215
  function readScoutPairingTrustedPeerCount(trustedPeersPath) {
12132
- if (!existsSync8(trustedPeersPath)) {
12216
+ if (!existsSync9(trustedPeersPath)) {
12133
12217
  return 0;
12134
12218
  }
12135
12219
  try {
12136
- const payload = JSON.parse(readFileSync5(trustedPeersPath, "utf8"));
12220
+ const payload = JSON.parse(readFileSync6(trustedPeersPath, "utf8"));
12137
12221
  return Array.isArray(payload) ? payload.length : 0;
12138
12222
  } catch {
12139
12223
  return 0;
@@ -12155,11 +12239,11 @@ function formatScoutPairingHistoryTimestamp(value) {
12155
12239
  }).format(date);
12156
12240
  }
12157
12241
  function readScoutPairingTrustedPeers(trustedPeersPath) {
12158
- if (!existsSync8(trustedPeersPath)) {
12242
+ if (!existsSync9(trustedPeersPath)) {
12159
12243
  return [];
12160
12244
  }
12161
12245
  try {
12162
- const payload = JSON.parse(readFileSync5(trustedPeersPath, "utf8"));
12246
+ const payload = JSON.parse(readFileSync6(trustedPeersPath, "utf8"));
12163
12247
  if (!Array.isArray(payload)) {
12164
12248
  return [];
12165
12249
  }
@@ -12183,7 +12267,7 @@ function readScoutPairingTrustedPeers(trustedPeersPath) {
12183
12267
  }
12184
12268
  }
12185
12269
  function readScoutPairingLogTail(logPath) {
12186
- if (!existsSync8(logPath)) {
12270
+ if (!existsSync9(logPath)) {
12187
12271
  return {
12188
12272
  body: "",
12189
12273
  updatedAtLabel: null,
@@ -12191,7 +12275,7 @@ function readScoutPairingLogTail(logPath) {
12191
12275
  truncated: false
12192
12276
  };
12193
12277
  }
12194
- const body = readFileSync5(logPath, "utf8");
12278
+ const body = readFileSync6(logPath, "utf8");
12195
12279
  const lines = body.split(/\r?\n/g);
12196
12280
  const visibleLines = lines.slice(-SCOUT_PAIRING_LOG_TAIL_LINE_LIMIT);
12197
12281
  const stats = statSync2(logPath);
@@ -12262,7 +12346,7 @@ function resolveScoutPairingRuntimeScriptPath() {
12262
12346
  join11(appRoot, "..", "..", "packages", "electron-app", "dist", "electron", SCOUT_PAIRING_RUNTIME_SCRIPT.replace(/\.ts$/, ".js"))
12263
12347
  ];
12264
12348
  for (const candidate of candidates) {
12265
- if (existsSync8(candidate)) {
12349
+ if (existsSync9(candidate)) {
12266
12350
  return candidate;
12267
12351
  }
12268
12352
  }
@@ -12479,7 +12563,7 @@ init_setup();
12479
12563
  init_support_paths();
12480
12564
  await init_local_agents();
12481
12565
  import { spawn as spawn5 } from "child_process";
12482
- import { existsSync as existsSync9 } from "fs";
12566
+ import { existsSync as existsSync10 } from "fs";
12483
12567
  import { homedir as homedir8 } from "os";
12484
12568
  import path4 from "path";
12485
12569
 
@@ -12600,7 +12684,7 @@ function defaultOnboardingContextRoot(explicitRoot, workspaceRoots, fallback) {
12600
12684
  return path4.resolve(expandHomePath5(chosenRoot));
12601
12685
  }
12602
12686
  function isExecutable3(candidate) {
12603
- return existsSync9(candidate);
12687
+ return existsSync10(candidate);
12604
12688
  }
12605
12689
  function resolveScoutElectronScoutExecutable() {
12606
12690
  const explicit = process.env.OPENSCOUT_SCOUT_BIN ?? process.env.SCOUT_BIN;
@@ -12702,7 +12786,7 @@ function buildOnboardingSteps(input) {
12702
12786
  }
12703
12787
  function resolveCurrentProjectConfigPath(onboardingContextRoot) {
12704
12788
  const candidate = path4.join(onboardingContextRoot, ".openscout", "project.json");
12705
- return existsSync9(candidate) ? candidate : null;
12789
+ return existsSync10(candidate) ? candidate : null;
12706
12790
  }
12707
12791
  async function loadScoutElectronSettingsBase(currentDirectory, services = {}, input = {}) {
12708
12792
  const settingsDirectory = resolveSettingsDirectory(currentDirectory);
@@ -12796,7 +12880,7 @@ function buildScoutElectronAppSettingsState(base, input) {
12796
12880
  return {
12797
12881
  root: compactHomePath4(normalizedRoot) ?? normalizedRoot,
12798
12882
  title: path4.basename(normalizedRoot) || normalizedRoot,
12799
- projectConfigPath: existsSync9(projectConfigFilePath) ? compactHomePath4(projectConfigFilePath) ?? projectConfigFilePath : null
12883
+ projectConfigPath: existsSync10(projectConfigFilePath) ? compactHomePath4(projectConfigFilePath) ?? projectConfigFilePath : null
12800
12884
  };
12801
12885
  }),
12802
12886
  workspaceRootsNote: "Scan folders are user-configured. Scout walks them recursively to find repos, project roots, and harness evidence.",
@@ -13196,11 +13280,11 @@ function runOptionalCommand3(command, args) {
13196
13280
  }
13197
13281
  }
13198
13282
  function readPackageVersion(candidate) {
13199
- if (!existsSync10(candidate)) {
13283
+ if (!existsSync11(candidate)) {
13200
13284
  return null;
13201
13285
  }
13202
13286
  try {
13203
- const payload = JSON.parse(readFileSync6(candidate, "utf8"));
13287
+ const payload = JSON.parse(readFileSync7(candidate, "utf8"));
13204
13288
  if (typeof payload.version === "string" && payload.version.trim().length > 0) {
13205
13289
  return payload.version.trim();
13206
13290
  }
@@ -13373,8 +13457,8 @@ function appModeLabel() {
13373
13457
  try {
13374
13458
  const appRoot = resolveScoutAppRoot();
13375
13459
  const packageJsonPath = path5.join(appRoot, "package.json");
13376
- if (existsSync10(packageJsonPath)) {
13377
- const payload = JSON.parse(readFileSync6(packageJsonPath, "utf8"));
13460
+ if (existsSync11(packageJsonPath)) {
13461
+ const payload = JSON.parse(readFileSync7(packageJsonPath, "utf8"));
13378
13462
  if (payload.name === "@scout/electron-app") {
13379
13463
  return "packaged";
13380
13464
  }
@@ -13504,7 +13588,7 @@ async function tailScoutLogSource(source, tailLines = DEFAULT_LOG_TAIL_LINES) {
13504
13588
  let truncated = false;
13505
13589
  let foundAny = false;
13506
13590
  for (const filePath of source.paths) {
13507
- if (!existsSync10(filePath)) {
13591
+ if (!existsSync11(filePath)) {
13508
13592
  continue;
13509
13593
  }
13510
13594
  foundAny = true;
@@ -13769,7 +13853,7 @@ async function submitScoutElectronFeedbackReport(input, currentDirectory = proce
13769
13853
  }
13770
13854
 
13771
13855
  // apps/desktop/src/app/electron/host.ts
13772
- import { existsSync as existsSync11 } from "fs";
13856
+ import { existsSync as existsSync12 } from "fs";
13773
13857
  import { stat as stat5 } from "fs/promises";
13774
13858
  import path6 from "path";
13775
13859
  function expandHomePath6(value) {
@@ -13809,16 +13893,16 @@ async function revealScoutElectronPath(filePath, host = {}) {
13809
13893
  if (!targetPath) {
13810
13894
  return false;
13811
13895
  }
13812
- if (existsSync11(targetPath)) {
13896
+ if (existsSync12(targetPath)) {
13813
13897
  try {
13814
13898
  const targetStats = await stat5(targetPath);
13815
13899
  if (targetStats.isDirectory()) {
13816
13900
  if (!host.openPath) {
13817
13901
  throw new Error("Scout path opening is unavailable.");
13818
13902
  }
13819
- const errorMessage2 = await host.openPath(targetPath);
13820
- if (errorMessage2) {
13821
- throw new Error(errorMessage2);
13903
+ const errorMessage3 = await host.openPath(targetPath);
13904
+ if (errorMessage3) {
13905
+ throw new Error(errorMessage3);
13822
13906
  }
13823
13907
  return true;
13824
13908
  }
@@ -14052,7 +14136,7 @@ function releaseScoutKeepAliveLease(leaseId) {
14052
14136
 
14053
14137
  // apps/desktop/src/app/host/agent-session.ts
14054
14138
  import { execFileSync as execFileSync6 } from "child_process";
14055
- import { existsSync as existsSync12 } from "fs";
14139
+ import { existsSync as existsSync13 } from "fs";
14056
14140
  import { open as open3 } from "fs/promises";
14057
14141
  import path7 from "path";
14058
14142
  init_support_paths();
@@ -14205,7 +14289,7 @@ async function readAgentSessionLogs(agentId, tailLines) {
14205
14289
  let foundAny = false;
14206
14290
  let targetPath = null;
14207
14291
  for (const filePath of sources) {
14208
- if (!existsSync12(filePath)) {
14292
+ if (!existsSync13(filePath)) {
14209
14293
  continue;
14210
14294
  }
14211
14295
  foundAny = true;
@@ -14384,9 +14468,9 @@ async function openScoutElectronAgentSession(agentId, host = {}) {
14384
14468
  if (!host.openPath) {
14385
14469
  throw new Error("Scout agent-session path opening is unavailable.");
14386
14470
  }
14387
- const errorMessage2 = await host.openPath(targetPath);
14388
- if (errorMessage2) {
14389
- throw new Error(errorMessage2);
14471
+ const errorMessage3 = await host.openPath(targetPath);
14472
+ if (errorMessage3) {
14473
+ throw new Error(errorMessage3);
14390
14474
  }
14391
14475
  return true;
14392
14476
  }
@@ -15116,7 +15200,7 @@ async function deriveNewAgentName(projectName, branch, harness) {
15116
15200
  async function createGitWorktree(projectRoot, agentName) {
15117
15201
  const { execSync: execSync2 } = await import("child_process");
15118
15202
  const { join: join12 } = await import("path");
15119
- const { mkdirSync: mkdirSync4, existsSync: existsSync13 } = await import("fs");
15203
+ const { mkdirSync: mkdirSync4, existsSync: existsSync14 } = await import("fs");
15120
15204
  try {
15121
15205
  execSync2("git rev-parse --git-dir", { cwd: projectRoot, stdio: "pipe" });
15122
15206
  } catch {
@@ -15125,7 +15209,7 @@ async function createGitWorktree(projectRoot, agentName) {
15125
15209
  const branchName = `scout/${agentName}`;
15126
15210
  const worktreeDir = join12(projectRoot, ".scout-worktrees");
15127
15211
  const worktreePath = join12(worktreeDir, agentName);
15128
- if (existsSync13(worktreePath)) {
15212
+ if (existsSync14(worktreePath)) {
15129
15213
  return { path: worktreePath, branch: branchName };
15130
15214
  }
15131
15215
  mkdirSync4(worktreeDir, { recursive: true });