@openscout/scout 0.2.57 → 0.2.58

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
@@ -2277,6 +2277,7 @@ function createBuiltInHarnessCatalog() {
2277
2277
  anyOf: entry.readiness.anyOf ? [...entry.readiness.anyOf] : undefined
2278
2278
  } : undefined,
2279
2279
  launch: entry.launch ? { ...entry.launch, args: [...entry.launch.args] } : undefined,
2280
+ resume: entry.resume ? { ...entry.resume } : undefined,
2280
2281
  resolveEnv: entry.resolveEnv ? [...entry.resolveEnv] : undefined,
2281
2282
  capabilities: [...entry.capabilities],
2282
2283
  metadata: entry.metadata ? { ...entry.metadata } : undefined
@@ -2294,6 +2295,7 @@ function mergeHarnessCatalogEntries(baseEntries, overrides = {}) {
2294
2295
  install: mergeInstall(entry.install, override.install),
2295
2296
  readiness: mergeReadiness(entry.readiness, override.readiness),
2296
2297
  launch: mergeLaunch(entry.launch, override.launch),
2298
+ resume: override.resume && entry.resume ? { ...entry.resume, ...override.resume } : entry.resume,
2297
2299
  tags: override.tags ? [...override.tags] : entry.tags,
2298
2300
  capabilities: override.capabilities ? [...override.capabilities] : entry.capabilities,
2299
2301
  resolveEnv: override.resolveEnv ? [...override.resolveEnv] : entry.resolveEnv,
@@ -2322,6 +2324,7 @@ function mergeHarnessCatalogEntries(baseEntries, overrides = {}) {
2322
2324
  install: mergeInstall(undefined, override.install),
2323
2325
  readiness: mergeReadiness(undefined, override.readiness),
2324
2326
  launch: mergeLaunch(undefined, override.launch),
2327
+ resume: override.resume?.command && override.resume?.sessionFlag ? { command: override.resume.command, sessionFlag: override.resume.sessionFlag, cwdFlag: override.resume.cwdFlag } : undefined,
2325
2328
  resolveEnv: override.resolveEnv ? [...override.resolveEnv] : undefined,
2326
2329
  capabilities: [...override.capabilities],
2327
2330
  metadata: override.metadata ? { ...override.metadata } : undefined
@@ -2474,6 +2477,11 @@ var init_harness_catalog = __esm(() => {
2474
2477
  loginCommand: "claude login",
2475
2478
  notReadyMessage: "Claude is installed but not authenticated yet."
2476
2479
  },
2480
+ resume: {
2481
+ command: "claude",
2482
+ sessionFlag: "--resume",
2483
+ cwdFlag: "--cwd"
2484
+ },
2477
2485
  capabilities: ["chat", "invoke", "deliver", "summarize", "review"]
2478
2486
  },
2479
2487
  {
@@ -2505,6 +2513,11 @@ var init_harness_catalog = __esm(() => {
2505
2513
  loginCommand: "codex login",
2506
2514
  notReadyMessage: "Codex is installed but not authenticated yet."
2507
2515
  },
2516
+ resume: {
2517
+ command: "codex",
2518
+ sessionFlag: "--thread",
2519
+ cwdFlag: "--cwd"
2520
+ },
2508
2521
  capabilities: ["chat", "invoke", "deliver", "review", "execute"]
2509
2522
  }
2510
2523
  ];
@@ -4684,7 +4697,8 @@ function buildManagedAgentShellExports(options) {
4684
4697
  // ../runtime/src/claude-stream-json.ts
4685
4698
  import { randomUUID } from "crypto";
4686
4699
  import { spawn } from "child_process";
4687
- import { appendFile, mkdir as mkdir3, readFile as readFile4, rm as rm2, writeFile as writeFile3 } from "fs/promises";
4700
+ import { appendFile, mkdir as mkdir3, readFile as readFile4, writeFile as writeFile3 } from "fs/promises";
4701
+ import { existsSync as existsSync4, readFileSync as readFileSync2 } from "fs";
4688
4702
  import { join as join5 } from "path";
4689
4703
  function resolveClaudeStreamJsonOutput(result, fallbackParts) {
4690
4704
  const trimmedResult = result?.trim();
@@ -4699,19 +4713,57 @@ function sessionKey(options) {
4699
4713
  function errorMessage(error) {
4700
4714
  return error instanceof Error ? error.message : String(error);
4701
4715
  }
4702
- async function readOptionalFile(filePath) {
4716
+ function readSessionCatalogSync(runtimeDirectory) {
4717
+ const catalogPath = join5(runtimeDirectory, SESSION_CATALOG_FILENAME);
4703
4718
  try {
4704
- const raw = await readFile4(filePath, "utf8");
4705
- const trimmed = raw.trim();
4706
- return trimmed || null;
4719
+ if (!existsSync4(catalogPath)) {
4720
+ const legacyPath = join5(runtimeDirectory, "claude-session-id.txt");
4721
+ if (existsSync4(legacyPath)) {
4722
+ const legacyId = readFileSync2(legacyPath, "utf8").trim();
4723
+ if (legacyId) {
4724
+ return {
4725
+ activeSessionId: legacyId,
4726
+ sessions: [{ id: legacyId, startedAt: Date.now(), cwd: "" }]
4727
+ };
4728
+ }
4729
+ }
4730
+ return { activeSessionId: null, sessions: [] };
4731
+ }
4732
+ const raw = readFileSync2(catalogPath, "utf8").trim();
4733
+ if (!raw)
4734
+ return { activeSessionId: null, sessions: [] };
4735
+ const parsed = JSON.parse(raw);
4736
+ return {
4737
+ activeSessionId: parsed.activeSessionId ?? null,
4738
+ sessions: Array.isArray(parsed.sessions) ? parsed.sessions : []
4739
+ };
4707
4740
  } catch {
4708
- return null;
4741
+ return { activeSessionId: null, sessions: [] };
4709
4742
  }
4710
4743
  }
4744
+ async function readSessionCatalog(runtimeDirectory) {
4745
+ return readSessionCatalogSync(runtimeDirectory);
4746
+ }
4747
+ async function writeSessionCatalog(runtimeDirectory, catalog) {
4748
+ const catalogPath = join5(runtimeDirectory, SESSION_CATALOG_FILENAME);
4749
+ await writeFile3(catalogPath, JSON.stringify(catalog, null, 2) + `
4750
+ `);
4751
+ }
4752
+ function catalogRecordSession(catalog, sessionId, cwd) {
4753
+ const now = Date.now();
4754
+ const sessions = catalog.sessions.map((s) => s.id === catalog.activeSessionId && !s.endedAt ? { ...s, endedAt: now } : s);
4755
+ if (!sessions.some((s) => s.id === sessionId)) {
4756
+ sessions.push({ id: sessionId, startedAt: now, cwd });
4757
+ }
4758
+ while (sessions.length > SESSION_CATALOG_MAX_ENTRIES) {
4759
+ sessions.shift();
4760
+ }
4761
+ return { activeSessionId: sessionId, sessions };
4762
+ }
4711
4763
 
4712
4764
  class ClaudeStreamJsonSession {
4713
4765
  options;
4714
- sessionStatePath;
4766
+ catalogDirectory;
4715
4767
  stdoutLogPath;
4716
4768
  stderrLogPath;
4717
4769
  process = null;
@@ -4722,7 +4774,7 @@ class ClaudeStreamJsonSession {
4722
4774
  lastConfigSignature;
4723
4775
  constructor(options) {
4724
4776
  this.options = options;
4725
- this.sessionStatePath = join5(options.runtimeDirectory, "claude-session-id.txt");
4777
+ this.catalogDirectory = options.runtimeDirectory;
4726
4778
  this.stdoutLogPath = join5(options.logsDirectory, "stdout.log");
4727
4779
  this.stderrLogPath = join5(options.logsDirectory, "stderr.log");
4728
4780
  this.lastConfigSignature = this.configSignature(options);
@@ -4828,7 +4880,9 @@ class ClaudeStreamJsonSession {
4828
4880
  }
4829
4881
  if (options.resetSession) {
4830
4882
  this.claudeSessionId = null;
4831
- await rm2(this.sessionStatePath, { force: true });
4883
+ const catalog = await readSessionCatalog(this.catalogDirectory);
4884
+ catalog.activeSessionId = null;
4885
+ await writeSessionCatalog(this.catalogDirectory, catalog);
4832
4886
  }
4833
4887
  }
4834
4888
  configSignature(options) {
@@ -4857,7 +4911,8 @@ class ClaudeStreamJsonSession {
4857
4911
  await mkdir3(this.options.runtimeDirectory, { recursive: true });
4858
4912
  await mkdir3(this.options.logsDirectory, { recursive: true });
4859
4913
  await writeFile3(join5(this.options.runtimeDirectory, "prompt.txt"), this.options.systemPrompt);
4860
- this.claudeSessionId = await readOptionalFile(this.sessionStatePath);
4914
+ const catalog = await readSessionCatalog(this.catalogDirectory);
4915
+ this.claudeSessionId = catalog.activeSessionId;
4861
4916
  const args = [
4862
4917
  "--verbose",
4863
4918
  "--print",
@@ -4936,8 +4991,11 @@ class ClaudeStreamJsonSession {
4936
4991
  const nextSessionId = event.session_id ?? event.sessionId ?? null;
4937
4992
  if (nextSessionId && nextSessionId !== this.claudeSessionId) {
4938
4993
  this.claudeSessionId = nextSessionId;
4939
- writeFile3(this.sessionStatePath, `${nextSessionId}
4940
- `);
4994
+ (async () => {
4995
+ const catalog = await readSessionCatalog(this.catalogDirectory);
4996
+ const updated = catalogRecordSession(catalog, nextSessionId, this.options.cwd);
4997
+ await writeSessionCatalog(this.catalogDirectory, updated);
4998
+ })();
4941
4999
  }
4942
5000
  return;
4943
5001
  }
@@ -5000,14 +5058,16 @@ async function shutdownClaudeStreamJsonAgent(options, shutdownOptions = {}) {
5000
5058
  const session = sessions.get(key);
5001
5059
  if (!session) {
5002
5060
  if (shutdownOptions.resetSession) {
5003
- await rm2(join5(options.runtimeDirectory, "claude-session-id.txt"), { force: true });
5061
+ const catalog = await readSessionCatalog(options.runtimeDirectory);
5062
+ catalog.activeSessionId = null;
5063
+ await writeSessionCatalog(options.runtimeDirectory, catalog);
5004
5064
  }
5005
5065
  return;
5006
5066
  }
5007
5067
  sessions.delete(key);
5008
5068
  await session.shutdown(shutdownOptions);
5009
5069
  }
5010
- var sessions;
5070
+ var SESSION_CATALOG_FILENAME = "session-catalog.json", SESSION_CATALOG_MAX_ENTRIES = 64, sessions;
5011
5071
  var init_claude_stream_json = __esm(() => {
5012
5072
  sessions = new Map;
5013
5073
  });
@@ -6184,7 +6244,7 @@ class ClaudeCodeHistoryParser {
6184
6244
  var init_history = () => {};
6185
6245
 
6186
6246
  // ../agent-sessions/src/adapters/claude-code.ts
6187
- import { existsSync as existsSync4, readdirSync, statSync as statSync2 } from "fs";
6247
+ import { existsSync as existsSync5, readdirSync, statSync as statSync2 } from "fs";
6188
6248
  import { homedir as homedir4 } from "os";
6189
6249
  import { join as join6 } from "path";
6190
6250
  function resolveClaudeResumeContext(config) {
@@ -6194,7 +6254,7 @@ function resolveClaudeResumeContext(config) {
6194
6254
  return null;
6195
6255
  }
6196
6256
  const projectsRoot = join6(homedir4(), ".claude", "projects");
6197
- if (!existsSync4(projectsRoot)) {
6257
+ if (!existsSync5(projectsRoot)) {
6198
6258
  return null;
6199
6259
  }
6200
6260
  let projectSlugs;
@@ -6205,7 +6265,7 @@ function resolveClaudeResumeContext(config) {
6205
6265
  }
6206
6266
  for (const slug of projectSlugs) {
6207
6267
  const sessionPath = join6(projectsRoot, slug, `${resumeId}.jsonl`);
6208
- if (!existsSync4(sessionPath)) {
6268
+ if (!existsSync5(sessionPath)) {
6209
6269
  continue;
6210
6270
  }
6211
6271
  const cwd = decodeClaudeProjectsSlug2(slug);
@@ -6746,7 +6806,7 @@ Referenced files: ${prompt.files.join(", ")}` });
6746
6806
  });
6747
6807
 
6748
6808
  // ../agent-sessions/src/codex-launch-config.ts
6749
- import { accessSync, constants, existsSync as existsSync5 } from "fs";
6809
+ import { accessSync, constants, existsSync as existsSync6 } from "fs";
6750
6810
  import { homedir as homedir5 } from "os";
6751
6811
  import { basename as basename2, delimiter, dirname as dirname4, join as join7, resolve as resolve5 } from "path";
6752
6812
  import { fileURLToPath as fileURLToPath3 } from "url";
@@ -6830,7 +6890,7 @@ function resolveRepoScoutScript(currentDirectory) {
6830
6890
  for (const start of starts) {
6831
6891
  for (const candidate of ancestorChain(start)) {
6832
6892
  const scriptPath = join7(candidate, "apps", "desktop", "bin", "scout.ts");
6833
- if (existsSync5(scriptPath)) {
6893
+ if (existsSync6(scriptPath)) {
6834
6894
  return scriptPath;
6835
6895
  }
6836
6896
  }
@@ -6920,7 +6980,7 @@ function errorMessage2(error) {
6920
6980
  }
6921
6981
  return String(error);
6922
6982
  }
6923
- async function readOptionalFile2(filePath) {
6983
+ async function readOptionalFile(filePath) {
6924
6984
  try {
6925
6985
  const raw = await readFile5(filePath, "utf8");
6926
6986
  const trimmed = raw.trim();
@@ -7267,7 +7327,7 @@ var init_codex = __esm(() => {
7267
7327
  async resumeOrStartThread() {
7268
7328
  const options = this.codexOptions;
7269
7329
  const requestedThreadId = options.threadId?.trim() || null;
7270
- const storedThreadId = requestedThreadId ?? await readOptionalFile2(this.threadIdPath);
7330
+ const storedThreadId = requestedThreadId ?? await readOptionalFile(this.threadIdPath);
7271
7331
  if (storedThreadId) {
7272
7332
  try {
7273
7333
  const resumed = await this.request("thread/resume", {
@@ -9483,7 +9543,7 @@ function isServerRequest2(message) {
9483
9543
  function isNotification2(message) {
9484
9544
  return Boolean(message && typeof message === "object" && "method" in message && !("id" in message));
9485
9545
  }
9486
- async function readOptionalFile3(filePath) {
9546
+ async function readOptionalFile2(filePath) {
9487
9547
  try {
9488
9548
  const raw = await readFile6(filePath, "utf8");
9489
9549
  const trimmed = raw.trim();
@@ -9760,7 +9820,7 @@ class CodexAppServerSession {
9760
9820
  }
9761
9821
  async resumeOrStartThread() {
9762
9822
  const requestedThreadId = this.options.threadId?.trim() || null;
9763
- const storedThreadId = requestedThreadId ?? await readOptionalFile3(this.threadIdPath);
9823
+ const storedThreadId = requestedThreadId ?? await readOptionalFile2(this.threadIdPath);
9764
9824
  if (storedThreadId) {
9765
9825
  try {
9766
9826
  const resumed = await this.request("thread/resume", {
@@ -10191,7 +10251,7 @@ function buildCollaborationContractPrompt(agentId) {
10191
10251
 
10192
10252
  // ../runtime/src/broker-service.ts
10193
10253
  import { spawnSync } from "child_process";
10194
- import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync2, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
10254
+ import { existsSync as existsSync7, mkdirSync as mkdirSync2, readFileSync as readFileSync3, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
10195
10255
  import { homedir as homedir7 } from "os";
10196
10256
  import { basename as basename3, dirname as dirname5, join as join10, resolve as resolve6 } from "path";
10197
10257
  import { fileURLToPath as fileURLToPath4 } from "url";
@@ -10230,7 +10290,7 @@ function runtimePackageDir() {
10230
10290
  return resolve6(moduleDir, "..");
10231
10291
  }
10232
10292
  function isInstalledRuntimePackageDir(candidate) {
10233
- return existsSync6(join10(candidate, "package.json")) && existsSync6(join10(candidate, "bin", "openscout-runtime.mjs"));
10293
+ return existsSync7(join10(candidate, "package.json")) && existsSync7(join10(candidate, "bin", "openscout-runtime.mjs"));
10234
10294
  }
10235
10295
  function findGlobalRuntimeDir() {
10236
10296
  const candidates = [
@@ -10261,7 +10321,7 @@ function findWorkspaceRuntimeDir(startDir) {
10261
10321
  let current = resolve6(startDir);
10262
10322
  while (true) {
10263
10323
  const candidate = join10(current, "packages", "runtime");
10264
- if (existsSync6(join10(candidate, "package.json")) && existsSync6(join10(candidate, "src"))) {
10324
+ if (existsSync7(join10(candidate, "package.json")) && existsSync7(join10(candidate, "src"))) {
10265
10325
  return candidate;
10266
10326
  }
10267
10327
  const parent = dirname5(current);
@@ -10275,18 +10335,18 @@ function resolveBunExecutable2() {
10275
10335
  if (explicit && explicit.trim().length > 0) {
10276
10336
  return explicit;
10277
10337
  }
10278
- if (basename3(process.execPath).startsWith("bun") && existsSync6(process.execPath)) {
10338
+ if (basename3(process.execPath).startsWith("bun") && existsSync7(process.execPath)) {
10279
10339
  return process.execPath;
10280
10340
  }
10281
10341
  const pathEntries = (process.env.PATH ?? "").split(":").filter(Boolean);
10282
10342
  for (const entry of pathEntries) {
10283
10343
  const candidate = join10(entry, "bun");
10284
- if (existsSync6(candidate)) {
10344
+ if (existsSync7(candidate)) {
10285
10345
  return candidate;
10286
10346
  }
10287
10347
  }
10288
10348
  const homeBun = join10(homedir7(), ".bun", "bin", "bun");
10289
- if (existsSync6(homeBun)) {
10349
+ if (existsSync7(homeBun)) {
10290
10350
  return homeBun;
10291
10351
  }
10292
10352
  return "bun";
@@ -10476,10 +10536,10 @@ function launchctlPath() {
10476
10536
  return "/bin/launchctl";
10477
10537
  }
10478
10538
  function readLogLines(path) {
10479
- if (!existsSync6(path)) {
10539
+ if (!existsSync7(path)) {
10480
10540
  return [];
10481
10541
  }
10482
- return readFileSync2(path, "utf8").split(`
10542
+ return readFileSync3(path, "utf8").split(`
10483
10543
  `).map((line) => line.trim()).filter(Boolean);
10484
10544
  }
10485
10545
  function isPackageScriptBanner(line) {
@@ -10576,7 +10636,7 @@ async function brokerServiceStatus(config = resolveBrokerServiceConfig()) {
10576
10636
  ensureServiceDirectories(config);
10577
10637
  const launchctl = inspectLaunchctl(config);
10578
10638
  const health = await fetchHealthSnapshot(config);
10579
- const installed = existsSync6(config.launchAgentPath);
10639
+ const installed = existsSync7(config.launchAgentPath);
10580
10640
  const lastLogLine = health.reachable ? readLastLogLine([config.stdoutLogPath, config.stderrLogPath]) : readLastLogLine([config.stderrLogPath, config.stdoutLogPath]);
10581
10641
  return {
10582
10642
  label: config.label,
@@ -10638,7 +10698,7 @@ async function restartBrokerService(config = resolveBrokerServiceConfig()) {
10638
10698
  }
10639
10699
  async function uninstallBrokerService(config = resolveBrokerServiceConfig()) {
10640
10700
  await stopBrokerService(config);
10641
- if (existsSync6(config.launchAgentPath)) {
10701
+ if (existsSync7(config.launchAgentPath)) {
10642
10702
  rmSync2(config.launchAgentPath, { force: true });
10643
10703
  }
10644
10704
  return brokerServiceStatus(config);
@@ -10717,7 +10777,7 @@ var init_local_agent_template = __esm(() => {
10717
10777
 
10718
10778
  // ../runtime/src/local-agents.ts
10719
10779
  import { execFileSync as execFileSync3, execSync } from "child_process";
10720
- import { existsSync as existsSync7, readFileSync as readFileSync3 } from "fs";
10780
+ import { existsSync as existsSync8, readFileSync as readFileSync4 } from "fs";
10721
10781
  import { mkdir as mkdir6, rm as rm5, stat as stat3, writeFile as writeFile6 } from "fs/promises";
10722
10782
  import { basename as basename4, dirname as dirname6, join as join11, resolve as resolve7 } from "path";
10723
10783
  import { fileURLToPath as fileURLToPath5 } from "url";
@@ -10730,10 +10790,10 @@ function resolveProjectsRoot(projectPath) {
10730
10790
  }
10731
10791
  try {
10732
10792
  const supportPaths = resolveOpenScoutSupportPaths();
10733
- if (!existsSync7(supportPaths.settingsPath)) {
10793
+ if (!existsSync8(supportPaths.settingsPath)) {
10734
10794
  return dirname6(projectPath);
10735
10795
  }
10736
- const raw = JSON.parse(readFileSync3(supportPaths.settingsPath, "utf8"));
10796
+ const raw = JSON.parse(readFileSync4(supportPaths.settingsPath, "utf8"));
10737
10797
  const workspaceRoot = raw.discovery?.workspaceRoots?.find((entry) => typeof entry === "string" && entry.trim().length > 0);
10738
10798
  return workspaceRoot ? resolve7(workspaceRoot) : dirname6(projectPath);
10739
10799
  } catch {
@@ -10746,8 +10806,14 @@ function resolveBrokerUrl() {
10746
10806
  function nowSeconds2() {
10747
10807
  return Math.floor(Date.now() / 1000);
10748
10808
  }
10809
+ function scoutCliPath() {
10810
+ return join11(OPENSCOUT_REPO_ROOT, "packages", "cli", "bin", "scout.mjs");
10811
+ }
10812
+ function legacyNodeBrokerRelayCommand() {
10813
+ return `node ${JSON.stringify(scoutCliPath())}`;
10814
+ }
10749
10815
  function brokerRelayCommand() {
10750
- return `node ${JSON.stringify(join11(OPENSCOUT_REPO_ROOT, "packages", "cli", "bin", "scout.mjs"))}`;
10816
+ return `bun ${JSON.stringify(scoutCliPath())}`;
10751
10817
  }
10752
10818
  function titleCaseLocalAgentName(value) {
10753
10819
  return value.split(/[-_.\s]+/).filter(Boolean).map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1)).join(" ");
@@ -10760,7 +10826,7 @@ function resolveScoutSkillPath() {
10760
10826
  join11(process.env.HOME ?? "", ".agents", "skills", "relay-agent-comms", "SKILL.md")
10761
10827
  ];
10762
10828
  for (const path of candidatePaths) {
10763
- if (existsSync7(path)) {
10829
+ if (existsSync8(path)) {
10764
10830
  return path;
10765
10831
  }
10766
10832
  }
@@ -10956,7 +11022,7 @@ function buildLegacyBrokerBackedRelayPrompt(agentId, projectName, projectPath, r
10956
11022
  function legacyLocalAgentSystemPromptCandidates(agentId, projectName, projectPath) {
10957
11023
  const relayHub = resolveRelayHub();
10958
11024
  const brokerUrl = resolveBrokerUrl();
10959
- const relayCommandBases = ["openscout relay", brokerRelayCommand()];
11025
+ const relayCommandBases = ["openscout relay", brokerRelayCommand(), legacyNodeBrokerRelayCommand()];
10960
11026
  const projectPathCandidates = projectPath.endsWith("/") ? [projectPath, projectPath.slice(0, -1)] : [projectPath, `${projectPath}/`];
10961
11027
  const candidates = new Set;
10962
11028
  for (const pathCandidate of projectPathCandidates) {
@@ -10967,12 +11033,28 @@ function legacyLocalAgentSystemPromptCandidates(agentId, projectName, projectPat
10967
11033
  }
10968
11034
  return Array.from(candidates);
10969
11035
  }
11036
+ function generatedLocalAgentSystemPromptCandidates(agentId, projectName, projectPath) {
11037
+ const baseContext = buildLocalAgentTemplateContext(agentId, projectName, projectPath);
11038
+ const relayCommands = [brokerRelayCommand(), legacyNodeBrokerRelayCommand()];
11039
+ const transportModes = [undefined, "codex_app_server", "claude_stream_json"];
11040
+ const candidates = new Set;
11041
+ for (const relayCommand of relayCommands) {
11042
+ const context = {
11043
+ ...baseContext,
11044
+ relayCommand
11045
+ };
11046
+ for (const transport of transportModes) {
11047
+ candidates.add(renderLocalAgentSystemPromptTemplate(buildLocalAgentSystemPromptTemplate(), context, transport ? { transport } : {}));
11048
+ }
11049
+ }
11050
+ return Array.from(candidates);
11051
+ }
10970
11052
  function normalizeLocalAgentSystemPrompt(agentId, projectName, projectPath, systemPrompt) {
10971
11053
  const trimmed = systemPrompt?.trim();
10972
11054
  if (!trimmed) {
10973
11055
  return;
10974
11056
  }
10975
- if (legacyLocalAgentSystemPromptCandidates(agentId, projectName, projectPath).includes(trimmed)) {
11057
+ if (legacyLocalAgentSystemPromptCandidates(agentId, projectName, projectPath).includes(trimmed) || generatedLocalAgentSystemPromptCandidates(agentId, projectName, projectPath).includes(trimmed)) {
10976
11058
  return;
10977
11059
  }
10978
11060
  return trimmed;
@@ -11460,7 +11542,7 @@ async function ensureLocalAgentOnline(agentName, record) {
11460
11542
  await new Promise((resolve8) => setTimeout(resolve8, 100));
11461
11543
  }
11462
11544
  if (!isLocalAgentSessionAlive(normalizedRecord.tmuxSession)) {
11463
- const stderrTail = existsSync7(stderrLogFile) ? readFileSync3(stderrLogFile, "utf8").trim().split(/\r?\n/).slice(-10).join(`
11545
+ const stderrTail = existsSync8(stderrLogFile) ? readFileSync4(stderrLogFile, "utf8").trim().split(/\r?\n/).slice(-10).join(`
11464
11546
  `).trim() : "";
11465
11547
  throw new Error(stderrTail ? `Relay agent ${agentName} failed to stay online:
11466
11548
  ${stderrTail}` : `Relay agent ${agentName} failed to stay online.`);
@@ -11828,6 +11910,29 @@ async function restartAllLocalAgents(options = {}) {
11828
11910
  }));
11829
11911
  return restarted.filter((agent) => Boolean(agent));
11830
11912
  }
11913
+ function readPersistedClaudeSessionId(agentName) {
11914
+ try {
11915
+ const runtimeDir = relayAgentRuntimeDirectory(agentName);
11916
+ const catalogPath = join11(runtimeDir, "session-catalog.json");
11917
+ if (existsSync8(catalogPath)) {
11918
+ const raw = readFileSync4(catalogPath, "utf8").trim();
11919
+ if (raw) {
11920
+ const catalog = JSON.parse(raw);
11921
+ if (typeof catalog.activeSessionId === "string" && catalog.activeSessionId.trim()) {
11922
+ return catalog.activeSessionId.trim();
11923
+ }
11924
+ }
11925
+ }
11926
+ const legacyPath = join11(runtimeDir, "claude-session-id.txt");
11927
+ if (existsSync8(legacyPath)) {
11928
+ const value = readFileSync4(legacyPath, "utf8").trim();
11929
+ return value || null;
11930
+ }
11931
+ return null;
11932
+ } catch {
11933
+ return null;
11934
+ }
11935
+ }
11831
11936
  function buildLocalAgentBinding(agentId, record, alive, nodeId, source) {
11832
11937
  const normalizedRecord = normalizeLocalAgentRecord(agentId, record);
11833
11938
  const definitionId = normalizedRecord.definitionId ?? agentId;
@@ -11835,6 +11940,7 @@ function buildLocalAgentBinding(agentId, record, alive, nodeId, source) {
11835
11940
  const projectRoot = normalizedRecord.projectRoot ?? normalizedRecord.cwd;
11836
11941
  const instance = buildRelayAgentInstance(definitionId, projectRoot);
11837
11942
  const actorId = instance.id;
11943
+ const externalSessionId = normalizedRecord.transport === "claude_stream_json" ? readPersistedClaudeSessionId(definitionId) : null;
11838
11944
  return {
11839
11945
  actor: {
11840
11946
  id: actorId,
@@ -11912,7 +12018,8 @@ function buildLocalAgentBinding(agentId, record, alive, nodeId, source) {
11912
12018
  selector: instance.selector,
11913
12019
  nodeQualifier: instance.nodeQualifier,
11914
12020
  workspaceQualifier: instance.workspaceQualifier,
11915
- branch: instance.branch
12021
+ branch: instance.branch,
12022
+ ...externalSessionId ? { externalSessionId } : {}
11916
12023
  }
11917
12024
  }
11918
12025
  };
@@ -12008,7 +12115,7 @@ var init_local_agents = __esm(async () => {
12008
12115
  });
12009
12116
 
12010
12117
  // ../runtime/src/user-config.ts
12011
- import { existsSync as existsSync8, readFileSync as readFileSync4, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "fs";
12118
+ import { existsSync as existsSync9, readFileSync as readFileSync5, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "fs";
12012
12119
  import { homedir as homedir8 } from "os";
12013
12120
  import { dirname as dirname7, join as join12 } from "path";
12014
12121
  function userConfigPath() {
@@ -12016,10 +12123,10 @@ function userConfigPath() {
12016
12123
  }
12017
12124
  function loadUserConfig() {
12018
12125
  const configPath = userConfigPath();
12019
- if (!existsSync8(configPath))
12126
+ if (!existsSync9(configPath))
12020
12127
  return {};
12021
12128
  try {
12022
- return JSON.parse(readFileSync4(configPath, "utf8"));
12129
+ return JSON.parse(readFileSync5(configPath, "utf8"));
12023
12130
  } catch {
12024
12131
  return {};
12025
12132
  }
@@ -43090,7 +43197,7 @@ var init_down = __esm(async () => {
43090
43197
  // ../../apps/desktop/src/app/host/runtime-service-client.ts
43091
43198
  import { spawn as spawn4 } from "child_process";
43092
43199
  import { basename as basename6, dirname as dirname8, join as join14 } from "path";
43093
- import { existsSync as existsSync9 } from "fs";
43200
+ import { existsSync as existsSync10 } from "fs";
43094
43201
  import { fileURLToPath as fileURLToPath6 } from "url";
43095
43202
  import { homedir as homedir9 } from "os";
43096
43203
  function tryWhich(executableName) {
@@ -43100,13 +43207,13 @@ function tryWhich(executableName) {
43100
43207
  if (!dir)
43101
43208
  continue;
43102
43209
  const candidate = join14(dir, executableName);
43103
- if (existsSync9(candidate)) {
43210
+ if (existsSync10(candidate)) {
43104
43211
  return candidate;
43105
43212
  }
43106
43213
  if (process.platform === "win32") {
43107
43214
  for (const ext of [".cmd", ".exe", ".bat"]) {
43108
43215
  const withExt = candidate + ext;
43109
- if (existsSync9(withExt))
43216
+ if (existsSync10(withExt))
43110
43217
  return withExt;
43111
43218
  }
43112
43219
  }
@@ -43118,7 +43225,7 @@ function findNodeModulesRuntimeBin() {
43118
43225
  let dir = dirname8(fileURLToPath6(import.meta.url));
43119
43226
  for (let i = 0;i < 24; i++) {
43120
43227
  const candidate = join14(dir, runtimeBinRel);
43121
- if (existsSync9(candidate))
43228
+ if (existsSync10(candidate))
43122
43229
  return candidate;
43123
43230
  const parent = dirname8(dir);
43124
43231
  if (parent === dir)
@@ -43126,7 +43233,7 @@ function findNodeModulesRuntimeBin() {
43126
43233
  dir = parent;
43127
43234
  }
43128
43235
  const bunGlobal = join14(homedir9(), ".bun", "install", "global", "node_modules", "@openscout", "runtime", "bin", "openscout-runtime.mjs");
43129
- if (existsSync9(bunGlobal))
43236
+ if (existsSync10(bunGlobal))
43130
43237
  return bunGlobal;
43131
43238
  return null;
43132
43239
  }
@@ -43134,7 +43241,7 @@ function findMonorepoOpenscoutRuntimeBin() {
43134
43241
  let dir = process.cwd();
43135
43242
  for (let i = 0;i < 24; i++) {
43136
43243
  const candidate = join14(dir, "packages", "runtime", "bin", "openscout-runtime.mjs");
43137
- if (existsSync9(candidate)) {
43244
+ if (existsSync10(candidate)) {
43138
43245
  return candidate;
43139
43246
  }
43140
43247
  const parent = dirname8(dir);
@@ -43147,7 +43254,7 @@ function findMonorepoOpenscoutRuntimeBin() {
43147
43254
  function resolveJavaScriptRuntimeExecutable() {
43148
43255
  const explicit = process.env.OPENSCOUT_RUNTIME_NODE_BIN?.trim();
43149
43256
  if (explicit) {
43150
- if (existsSync9(explicit)) {
43257
+ if (existsSync10(explicit)) {
43151
43258
  return explicit;
43152
43259
  }
43153
43260
  const found = tryWhich(explicit);
@@ -43173,7 +43280,7 @@ function resolveJavaScriptRuntimeExecutable() {
43173
43280
  function resolveRuntimeServiceEntrypoint() {
43174
43281
  const explicit = process.env.OPENSCOUT_RUNTIME_BIN?.trim();
43175
43282
  if (explicit) {
43176
- if (existsSync9(explicit)) {
43283
+ if (existsSync10(explicit)) {
43177
43284
  return explicit;
43178
43285
  }
43179
43286
  const found = tryWhich(explicit);
@@ -43450,16 +43557,16 @@ var init_service3 = __esm(() => {
43450
43557
  });
43451
43558
 
43452
43559
  // ../../apps/desktop/src/shared/paths.ts
43453
- import { existsSync as existsSync10, readFileSync as readFileSync5 } from "fs";
43560
+ import { existsSync as existsSync11, readFileSync as readFileSync6 } from "fs";
43454
43561
  import { dirname as dirname10, join as join16, resolve as resolve10 } from "path";
43455
43562
  import { fileURLToPath as fileURLToPath7 } from "url";
43456
43563
  function looksLikeWorkspaceRoot(candidate) {
43457
43564
  const packageJsonPath = join16(candidate, "package.json");
43458
- if (!existsSync10(packageJsonPath)) {
43565
+ if (!existsSync11(packageJsonPath)) {
43459
43566
  return false;
43460
43567
  }
43461
43568
  try {
43462
- const parsed = JSON.parse(readFileSync5(packageJsonPath, "utf8"));
43569
+ const parsed = JSON.parse(readFileSync6(packageJsonPath, "utf8"));
43463
43570
  return Array.isArray(parsed.workspaces);
43464
43571
  } catch {
43465
43572
  return false;
@@ -43467,18 +43574,18 @@ function looksLikeWorkspaceRoot(candidate) {
43467
43574
  }
43468
43575
  function looksLikePackagedAppRoot(candidate) {
43469
43576
  const packageJsonPath = join16(candidate, "package.json");
43470
- if (!existsSync10(packageJsonPath)) {
43577
+ if (!existsSync11(packageJsonPath)) {
43471
43578
  return false;
43472
43579
  }
43473
43580
  try {
43474
- const parsed = JSON.parse(readFileSync5(packageJsonPath, "utf8"));
43581
+ const parsed = JSON.parse(readFileSync6(packageJsonPath, "utf8"));
43475
43582
  return parsed.name === "@openscout/scout" || parsed.name === "@openscout/cli";
43476
43583
  } catch {
43477
43584
  return false;
43478
43585
  }
43479
43586
  }
43480
43587
  function looksLikeSourceAppRoot(candidate) {
43481
- return existsSync10(join16(candidate, "bin", "scout.ts"));
43588
+ return existsSync11(join16(candidate, "bin", "scout.ts"));
43482
43589
  }
43483
43590
  function findMatchingAncestor(startDirectory, predicate) {
43484
43591
  let current = resolve10(startDirectory);
@@ -43798,7 +43905,7 @@ var exports_env = {};
43798
43905
  __export(exports_env, {
43799
43906
  runEnvCommand: () => runEnvCommand
43800
43907
  });
43801
- import { existsSync as existsSync11 } from "fs";
43908
+ import { existsSync as existsSync12 } from "fs";
43802
43909
  import { join as join17 } from "path";
43803
43910
  function resolveCommandOnPath(command, env) {
43804
43911
  const pathValue = env.PATH ?? "";
@@ -43808,7 +43915,7 @@ function resolveCommandOnPath(command, env) {
43808
43915
  continue;
43809
43916
  }
43810
43917
  const candidate = join17(trimmed, command);
43811
- if (existsSync11(candidate)) {
43918
+ if (existsSync12(candidate)) {
43812
43919
  return candidate;
43813
43920
  }
43814
43921
  }
@@ -43820,7 +43927,7 @@ function resolveScoutBinPath(appRoot) {
43820
43927
  join17(appRoot, "bin", "scout.mjs")
43821
43928
  ];
43822
43929
  for (const candidate of candidates) {
43823
- if (existsSync11(candidate)) {
43930
+ if (existsSync12(candidate)) {
43824
43931
  return candidate;
43825
43932
  }
43826
43933
  }
@@ -43895,9 +44002,9 @@ var init_env = __esm(async () => {
43895
44002
 
43896
44003
  // ../runtime/src/local-config.ts
43897
44004
  import {
43898
- existsSync as existsSync12,
44005
+ existsSync as existsSync13,
43899
44006
  mkdirSync as mkdirSync4,
43900
- readFileSync as readFileSync6,
44007
+ readFileSync as readFileSync7,
43901
44008
  renameSync,
43902
44009
  writeFileSync as writeFileSync4
43903
44010
  } from "fs";
@@ -43911,10 +44018,10 @@ function localConfigPath() {
43911
44018
  }
43912
44019
  function loadLocalConfig() {
43913
44020
  const configPath = localConfigPath();
43914
- if (!existsSync12(configPath))
44021
+ if (!existsSync13(configPath))
43915
44022
  return { version: LOCAL_CONFIG_VERSION };
43916
44023
  try {
43917
- return validateLocalConfig(JSON.parse(readFileSync6(configPath, "utf8")));
44024
+ return validateLocalConfig(JSON.parse(readFileSync7(configPath, "utf8")));
43918
44025
  } catch {
43919
44026
  return { version: LOCAL_CONFIG_VERSION };
43920
44027
  }
@@ -43954,7 +44061,7 @@ function writeLocalConfig(config2) {
43954
44061
  renameSync(tmp, configPath);
43955
44062
  }
43956
44063
  function localConfigExists() {
43957
- return existsSync12(localConfigPath());
44064
+ return existsSync13(localConfigPath());
43958
44065
  }
43959
44066
  var LOCAL_CONFIG_VERSION = 1, DEFAULT_LOCAL_CONFIG;
43960
44067
  var init_local_config = __esm(() => {
@@ -46011,7 +46118,7 @@ __export(exports_menu, {
46011
46118
  parseMenuCommand: () => parseMenuCommand
46012
46119
  });
46013
46120
  import { spawnSync as spawnSync2 } from "child_process";
46014
- import { existsSync as existsSync13 } from "fs";
46121
+ import { existsSync as existsSync14 } from "fs";
46015
46122
  import { homedir as homedir11 } from "os";
46016
46123
  import { dirname as dirname12, join as join19, resolve as resolve12 } from "path";
46017
46124
  import { fileURLToPath as fileURLToPath8 } from "url";
@@ -46100,7 +46207,7 @@ function findRepoMenuHelper(startDirectory) {
46100
46207
  let current = resolve12(startDirectory);
46101
46208
  while (true) {
46102
46209
  const candidate = join19(current, "apps", "macos", "bin", "openscout-menu.ts");
46103
- if (existsSync13(candidate)) {
46210
+ if (existsSync14(candidate)) {
46104
46211
  return candidate;
46105
46212
  }
46106
46213
  const parent = dirname12(current);
@@ -46110,7 +46217,7 @@ function findRepoMenuHelper(startDirectory) {
46110
46217
  current = parent;
46111
46218
  }
46112
46219
  const sourceRelativeCandidate = fileURLToPath8(new URL("../../../../macos/bin/openscout-menu.ts", import.meta.url));
46113
- return existsSync13(sourceRelativeCandidate) ? sourceRelativeCandidate : null;
46220
+ return existsSync14(sourceRelativeCandidate) ? sourceRelativeCandidate : null;
46114
46221
  }
46115
46222
  function resolveRepoBundlePath(helperPath) {
46116
46223
  return resolve12(dirname12(helperPath), "..", "dist", MENU_BUNDLE_NAME);
@@ -46129,7 +46236,7 @@ function resolveInstalledMenuBundlePath(env) {
46129
46236
  return indexedPath;
46130
46237
  }
46131
46238
  for (const candidate of COMMON_MENU_BUNDLE_PATHS) {
46132
- if (existsSync13(candidate)) {
46239
+ if (existsSync14(candidate)) {
46133
46240
  return candidate;
46134
46241
  }
46135
46242
  }
@@ -46198,7 +46305,7 @@ function runWithRepoHelper(context, helperPath, command) {
46198
46305
  });
46199
46306
  const bundlePath = resolveRepoBundlePath(helperPath);
46200
46307
  const running = command.action === "quit" ? false : isMenuRunning(context.env);
46201
- const installed = existsSync13(bundlePath) || running;
46308
+ const installed = existsSync14(bundlePath) || running;
46202
46309
  return {
46203
46310
  action: command.action,
46204
46311
  mode: "repo-helper",
@@ -46290,6 +46397,26 @@ function parsePeers(status) {
46290
46397
  tags: peer.Tags ?? []
46291
46398
  }));
46292
46399
  }
46400
+ function parseSelf(status) {
46401
+ const self2 = status.Self;
46402
+ if (!self2) {
46403
+ return null;
46404
+ }
46405
+ return {
46406
+ id: self2.ID ?? self2.DNSName ?? self2.HostName ?? "self",
46407
+ name: self2.HostName ?? self2.DNSName ?? "self",
46408
+ dnsName: self2.DNSName,
46409
+ addresses: self2.TailscaleIPs ?? [],
46410
+ online: self2.Online ?? true,
46411
+ hostName: self2.HostName,
46412
+ os: self2.OS,
46413
+ tailnetName: status.CurrentTailnet?.Name,
46414
+ magicDnsSuffix: status.CurrentTailnet?.MagicDNSSuffix
46415
+ };
46416
+ }
46417
+ function isBackendRunning(status) {
46418
+ return (status.BackendState ?? "").trim().toLowerCase() === "running";
46419
+ }
46293
46420
  async function readStatusJsonFromFile(filePath) {
46294
46421
  const raw = await readFile9(filePath, "utf8");
46295
46422
  return parseStatusJson(raw);
@@ -46308,11 +46435,24 @@ async function readStatusJson() {
46308
46435
  }
46309
46436
  }
46310
46437
  async function readTailscalePeers() {
46438
+ const summary = await readTailscaleStatusSummary();
46439
+ if (!summary) {
46440
+ return [];
46441
+ }
46442
+ return summary.peers;
46443
+ }
46444
+ async function readTailscaleStatusSummary() {
46311
46445
  const status = await readStatusJson();
46312
46446
  if (!status) {
46313
- return [];
46447
+ return null;
46314
46448
  }
46315
- return parsePeers(status);
46449
+ return {
46450
+ backendState: status.BackendState ?? null,
46451
+ running: isBackendRunning(status),
46452
+ health: status.Health ?? [],
46453
+ peers: parsePeers(status),
46454
+ self: parseSelf(status)
46455
+ };
46316
46456
  }
46317
46457
  var execFileAsync;
46318
46458
  var init_tailscale = __esm(() => {
@@ -46342,9 +46482,13 @@ function readMeshEnvVars() {
46342
46482
  };
46343
46483
  }
46344
46484
  async function readTailscaleStatus() {
46345
- const peers = await readTailscalePeers();
46485
+ const summary = await readTailscaleStatusSummary();
46486
+ const peers = summary?.peers ?? [];
46346
46487
  return {
46347
- available: peers.length > 0,
46488
+ available: summary !== null,
46489
+ running: summary?.running ?? false,
46490
+ backendState: summary?.backendState ?? null,
46491
+ health: summary?.health ?? [],
46348
46492
  peers,
46349
46493
  onlineCount: peers.filter((p) => p.online).length
46350
46494
  };
@@ -46360,6 +46504,9 @@ function computeWarnings(health, localNode, nodes, tailscale) {
46360
46504
  } else if (localNode?.advertiseScope === "mesh" && localNode.brokerUrl && isLoopbackBrokerUrl(localNode.brokerUrl)) {
46361
46505
  warnings.push("Broker advertises mesh scope but is bound to loopback \u2014 peers cannot reach it. " + "Unset OPENSCOUT_BROKER_HOST (mesh default is 0.0.0.0) or use your Tailscale IP.");
46362
46506
  }
46507
+ if (tailscale.available && !tailscale.running) {
46508
+ warnings.push("Tailscale is installed but currently stopped on this machine. " + "Cached peers may appear, but the broker cannot reach them until Tailscale is running.");
46509
+ }
46363
46510
  const remoteNodes = Object.values(nodes).filter((n) => n.id !== localNode?.id);
46364
46511
  if (!tailscale.available && remoteNodes.length === 0) {
46365
46512
  warnings.push("No Tailscale peers found and no mesh seeds configured. " + "Install Tailscale or set OPENSCOUT_MESH_SEEDS.");
@@ -46525,7 +46672,7 @@ function renderMeshStatus(report) {
46525
46672
  }
46526
46673
  lines.push(` Broker: ${report.brokerUrl}`);
46527
46674
  lines.push(` Scope: ${report.localNode?.advertiseScope === "mesh" ? "mesh-reachable" : "local-only"}`);
46528
- const tsLabel = report.tailscale.available ? `available (${report.tailscale.onlineCount} peer${report.tailscale.onlineCount === 1 ? "" : "s"} online)` : "not available";
46675
+ const tsLabel = !report.tailscale.available ? "not available" : report.tailscale.running ? `running (${report.tailscale.onlineCount} peer${report.tailscale.onlineCount === 1 ? "" : "s"} online)` : `not running (${report.tailscale.backendState ?? "unknown"})`;
46529
46676
  lines.push(` Tailscale: ${tsLabel}`);
46530
46677
  const allNodes = Object.values(report.nodes);
46531
46678
  const remoteNodes = allNodes.filter((n) => n.id !== report.localNode?.id);
@@ -46559,7 +46706,8 @@ function renderMeshDoctor(report) {
46559
46706
  lines.push(` ID: ${report.localNode.id}`);
46560
46707
  lines.push(` Name: ${report.localNode.name}`);
46561
46708
  lines.push(` Mesh: ${report.localNode.meshId}`);
46562
- lines.push(` Broker URL: ${report.brokerUrl}`);
46709
+ lines.push(` Control URL: ${report.brokerUrl}`);
46710
+ lines.push(` Announced URL: ${report.localNode.brokerUrl ?? report.brokerUrl}`);
46563
46711
  lines.push(` Advertise scope: ${report.localNode.advertiseScope}`);
46564
46712
  if (report.localNode.hostName) {
46565
46713
  lines.push(` Hostname: ${report.localNode.hostName}`);
@@ -46570,7 +46718,11 @@ function renderMeshDoctor(report) {
46570
46718
  lines.push("");
46571
46719
  lines.push("Tailscale:");
46572
46720
  if (report.tailscale.available) {
46573
- lines.push(` Status: available (${report.tailscale.peers.length} peer${report.tailscale.peers.length === 1 ? "" : "s"})`);
46721
+ const state = report.tailscale.backendState ?? "unknown";
46722
+ lines.push(` Status: ${report.tailscale.running ? `running (${state})` : `not running (${state})`} (${report.tailscale.peers.length} peer${report.tailscale.peers.length === 1 ? "" : "s"})`);
46723
+ for (const detail of report.tailscale.health) {
46724
+ lines.push(` ! ${detail}`);
46725
+ }
46574
46726
  for (const peer of report.tailscale.peers) {
46575
46727
  const ips = peer.addresses.join(", ");
46576
46728
  const status = peer.online ? "online" : "offline";
@@ -46598,7 +46750,7 @@ function renderMeshDoctor(report) {
46598
46750
  }
46599
46751
  }
46600
46752
  lines.push("");
46601
- lines.push("Configuration:");
46753
+ lines.push("Client environment (this shell):");
46602
46754
  const env = report.envVars;
46603
46755
  lines.push(` OPENSCOUT_MESH_ID: ${env.meshId ?? "(default: openscout)"}`);
46604
46756
  lines.push(` OPENSCOUT_MESH_SEEDS: ${env.meshSeeds || "(not set)"}`);
@@ -46741,7 +46893,7 @@ var init_mesh2 = __esm(async () => {
46741
46893
  });
46742
46894
 
46743
46895
  // ../../apps/desktop/src/core/pairing/runtime/config.ts
46744
- import { existsSync as existsSync14, mkdirSync as mkdirSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
46896
+ import { existsSync as existsSync15, mkdirSync as mkdirSync5, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "fs";
46745
46897
  import { homedir as homedir12 } from "os";
46746
46898
  import path from "path";
46747
46899
  function pairingPaths() {
@@ -46758,11 +46910,11 @@ function pairingPaths() {
46758
46910
  }
46759
46911
  function loadPairingConfig() {
46760
46912
  const { configPath } = pairingPaths();
46761
- if (!existsSync14(configPath)) {
46913
+ if (!existsSync15(configPath)) {
46762
46914
  return {};
46763
46915
  }
46764
46916
  try {
46765
- const payload = JSON.parse(readFileSync7(configPath, "utf8"));
46917
+ const payload = JSON.parse(readFileSync8(configPath, "utf8"));
46766
46918
  return typeof payload === "object" && payload ? payload : {};
46767
46919
  } catch {
46768
46920
  return {};
@@ -48845,17 +48997,17 @@ var init_noise = __esm(() => {
48845
48997
  });
48846
48998
 
48847
48999
  // ../../apps/desktop/src/core/pairing/runtime/security/identity.ts
48848
- import { existsSync as existsSync15, mkdirSync as mkdirSync6, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "fs";
49000
+ import { existsSync as existsSync16, mkdirSync as mkdirSync6, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "fs";
48849
49001
  import { join as join20 } from "path";
48850
49002
  import { homedir as homedir13 } from "os";
48851
49003
  function loadOrCreateIdentity() {
48852
- if (existsSync15(IDENTITY_FILE)) {
49004
+ if (existsSync16(IDENTITY_FILE)) {
48853
49005
  return loadIdentity();
48854
49006
  }
48855
49007
  return createAndSaveIdentity();
48856
49008
  }
48857
49009
  function loadIdentity() {
48858
- const data = JSON.parse(readFileSync8(IDENTITY_FILE, "utf8"));
49010
+ const data = JSON.parse(readFileSync9(IDENTITY_FILE, "utf8"));
48859
49011
  return {
48860
49012
  publicKey: hexToBytes2(data.publicKey),
48861
49013
  privateKey: hexToBytes2(data.privateKey)
@@ -48873,9 +49025,9 @@ function createAndSaveIdentity() {
48873
49025
  return keyPair;
48874
49026
  }
48875
49027
  function loadTrustedPeers() {
48876
- if (!existsSync15(TRUSTED_PEERS_FILE))
49028
+ if (!existsSync16(TRUSTED_PEERS_FILE))
48877
49029
  return new Map;
48878
- const data = JSON.parse(readFileSync8(TRUSTED_PEERS_FILE, "utf8"));
49030
+ const data = JSON.parse(readFileSync9(TRUSTED_PEERS_FILE, "utf8"));
48879
49031
  return new Map(data.map((p) => [p.publicKey, p]));
48880
49032
  }
48881
49033
  function saveTrustedPeer(peer) {
@@ -49056,14 +49208,14 @@ var init_security2 = __esm(() => {
49056
49208
  });
49057
49209
 
49058
49210
  // ../../apps/desktop/src/core/pairing/runtime/runtime-state.ts
49059
- import { existsSync as existsSync16, mkdirSync as mkdirSync7, readFileSync as readFileSync9, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync7 } from "fs";
49211
+ import { existsSync as existsSync17, mkdirSync as mkdirSync7, readFileSync as readFileSync10, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync7 } from "fs";
49060
49212
  function readPairingRuntimeSnapshot() {
49061
49213
  const { runtimeStatePath } = pairingPaths();
49062
- if (!existsSync16(runtimeStatePath)) {
49214
+ if (!existsSync17(runtimeStatePath)) {
49063
49215
  return null;
49064
49216
  }
49065
49217
  try {
49066
- const parsed = JSON.parse(readFileSync9(runtimeStatePath, "utf8"));
49218
+ const parsed = JSON.parse(readFileSync10(runtimeStatePath, "utf8"));
49067
49219
  return parsed?.version === 1 ? parsed : null;
49068
49220
  } catch {
49069
49221
  return null;
@@ -49181,15 +49333,15 @@ var init_bridge = __esm(() => {
49181
49333
  });
49182
49334
 
49183
49335
  // ../../apps/desktop/src/core/pairing/runtime/bridge/config.ts
49184
- import { existsSync as existsSync17, readFileSync as readFileSync10 } from "fs";
49336
+ import { existsSync as existsSync18, readFileSync as readFileSync11 } from "fs";
49185
49337
  import { join as join22 } from "path";
49186
49338
  import { homedir as homedir15 } from "os";
49187
49339
  function loadConfigFile() {
49188
- if (!existsSync17(CONFIG_FILE)) {
49340
+ if (!existsSync18(CONFIG_FILE)) {
49189
49341
  return {};
49190
49342
  }
49191
49343
  try {
49192
- const raw = readFileSync10(CONFIG_FILE, "utf8");
49344
+ const raw = readFileSync11(CONFIG_FILE, "utf8");
49193
49345
  const parsed = JSON.parse(raw);
49194
49346
  return parsed;
49195
49347
  } catch (err) {
@@ -50102,7 +50254,7 @@ async function deriveNewAgentName(projectName, branch, harness) {
50102
50254
  async function createGitWorktree(projectRoot, agentName) {
50103
50255
  const { execSync: execSync2 } = await import("child_process");
50104
50256
  const { join: join24 } = await import("path");
50105
- const { mkdirSync: mkdirSync9, existsSync: existsSync18 } = await import("fs");
50257
+ const { mkdirSync: mkdirSync9, existsSync: existsSync19 } = await import("fs");
50106
50258
  try {
50107
50259
  execSync2("git rev-parse --git-dir", { cwd: projectRoot, stdio: "pipe" });
50108
50260
  } catch {
@@ -50111,7 +50263,7 @@ async function createGitWorktree(projectRoot, agentName) {
50111
50263
  const branchName = `scout/${agentName}`;
50112
50264
  const worktreeDir = join24(projectRoot, ".scout-worktrees");
50113
50265
  const worktreePath = join24(worktreeDir, agentName);
50114
- if (existsSync18(worktreePath)) {
50266
+ if (existsSync19(worktreePath)) {
50115
50267
  return { path: worktreePath, branch: branchName };
50116
50268
  }
50117
50269
  mkdirSync9(worktreeDir, { recursive: true });
@@ -50154,7 +50306,7 @@ var init_service5 = __esm(async () => {
50154
50306
  });
50155
50307
 
50156
50308
  // ../../apps/desktop/src/core/pairing/runtime/bridge/server.ts
50157
- import { readdirSync as readdirSync2, readFileSync as readFileSync11, realpathSync, statSync as statSync3 } from "fs";
50309
+ import { readdirSync as readdirSync2, readFileSync as readFileSync12, realpathSync, statSync as statSync3 } from "fs";
50158
50310
  import { execSync as execSync2 } from "child_process";
50159
50311
  import { basename as basename9, isAbsolute as isAbsolute3, join as join24, relative as relative2 } from "path";
50160
50312
  import { homedir as homedir18 } from "os";
@@ -50493,7 +50645,7 @@ async function handleRPCInner(bridge, req, deviceId) {
50493
50645
  return { id: req.id, error: { code: -32000, message: "Only .jsonl files can be read" } };
50494
50646
  }
50495
50647
  try {
50496
- const content = readFileSync11(p.path, "utf-8");
50648
+ const content = readFileSync12(p.path, "utf-8");
50497
50649
  const lines = content.split(`
50498
50650
  `).filter((l) => l.trim().length > 0);
50499
50651
  const trimmed = lines.length > 500 ? lines.slice(-500) : lines;
@@ -54747,7 +54899,7 @@ var init_thread_events2 = __esm(() => {
54747
54899
 
54748
54900
  // ../runtime/src/mobile-push.ts
54749
54901
  import { Database as Database2 } from "bun:sqlite";
54750
- import { mkdirSync as mkdirSync9, readFileSync as readFileSync12 } from "fs";
54902
+ import { mkdirSync as mkdirSync9, readFileSync as readFileSync13 } from "fs";
54751
54903
  import { connect as connectHttp2 } from "http2";
54752
54904
  import { createPrivateKey, sign as signWithKey } from "crypto";
54753
54905
  import { dirname as dirname13, join as join25 } from "path";
@@ -54918,7 +55070,7 @@ function loadApnsCredentials() {
54918
55070
  privateKeyPem = Buffer.from(inlineBase64, "base64").toString("utf8");
54919
55071
  }
54920
55072
  if (!privateKeyPem && path2) {
54921
- privateKeyPem = readFileSync12(path2, "utf8");
55073
+ privateKeyPem = readFileSync13(path2, "utf8");
54922
55074
  }
54923
55075
  if (!teamId || !keyId || !privateKeyPem) {
54924
55076
  return null;
@@ -55142,7 +55294,7 @@ var init_src2 = __esm(async () => {
55142
55294
  });
55143
55295
 
55144
55296
  // ../../apps/desktop/src/core/pairing/runtime/bridge/router.ts
55145
- import { readFileSync as readFileSync13, readdirSync as readdirSync3, realpathSync as realpathSync2, statSync as statSync4 } from "fs";
55297
+ import { readFileSync as readFileSync14, readdirSync as readdirSync3, realpathSync as realpathSync2, statSync as statSync4 } from "fs";
55146
55298
  import { execSync as execSync3 } from "child_process";
55147
55299
  import { basename as basename10, isAbsolute as isAbsolute4, join as join26, relative as relative3 } from "path";
55148
55300
  import { homedir as homedir19 } from "os";
@@ -55822,7 +55974,7 @@ var init_router = __esm(async () => {
55822
55974
  });
55823
55975
  }
55824
55976
  try {
55825
- const content = readFileSync13(input.path, "utf-8");
55977
+ const content = readFileSync14(input.path, "utf-8");
55826
55978
  const lines = content.split(`
55827
55979
  `).filter((l) => l.trim().length > 0);
55828
55980
  const trimmed = lines.length > 500 ? lines.slice(-500) : lines;
@@ -60775,11 +60927,11 @@ var BRIDGE_ABSENCE_GRACE_MS = 30000, ROOM_IDLE_TIMEOUT_MS = 60000;
60775
60927
 
60776
60928
  // ../../apps/desktop/src/core/pairing/runtime/relay-runtime.ts
60777
60929
  import { execSync as execSync4 } from "child_process";
60778
- import { existsSync as existsSync18, mkdirSync as mkdirSync11, readdirSync as readdirSync4 } from "fs";
60930
+ import { existsSync as existsSync19, mkdirSync as mkdirSync11, readdirSync as readdirSync4 } from "fs";
60779
60931
  import { homedir as homedir22 } from "os";
60780
60932
  import { join as join27 } from "path";
60781
60933
  function findStoredCerts() {
60782
- if (!existsSync18(PAIRING_DIR2)) {
60934
+ if (!existsSync19(PAIRING_DIR2)) {
60783
60935
  return null;
60784
60936
  }
60785
60937
  try {
@@ -61835,7 +61987,7 @@ __export(exports_server, {
61835
61987
  normalizeServerOpenPath: () => normalizeServerOpenPath
61836
61988
  });
61837
61989
  import { spawn as spawn5 } from "child_process";
61838
- import { existsSync as existsSync19 } from "fs";
61990
+ import { existsSync as existsSync20 } from "fs";
61839
61991
  import { dirname as dirname14, join as join28, resolve as resolve14 } from "path";
61840
61992
  import { fileURLToPath as fileURLToPath9 } from "url";
61841
61993
  function renderServerCommandHelp() {
@@ -61845,6 +61997,7 @@ function renderServerCommandHelp() {
61845
61997
  "Usage:",
61846
61998
  " scout server start [options]",
61847
61999
  " scout server open [options]",
62000
+ " scout server control-plane open [options] # legacy alias",
61848
62001
  "",
61849
62002
  "Subcommands:",
61850
62003
  " start Start the Scout web UI server.",
@@ -61868,14 +62021,18 @@ function resolveScoutWebServerEntry() {
61868
62021
  function resolveScoutControlPlaneWebServerEntry() {
61869
62022
  const mainDir = dirname14(fileURLToPath9(import.meta.url));
61870
62023
  const bundled = join28(mainDir, "scout-control-plane-web.mjs");
61871
- if (existsSync19(bundled)) {
62024
+ if (existsSync20(bundled)) {
61872
62025
  return bundled;
61873
62026
  }
61874
- const source = fileURLToPath9(new URL("../../server/control-plane-index.ts", import.meta.url));
61875
- if (existsSync19(source)) {
62027
+ const source = fileURLToPath9(new URL("../../../../../packages/web/server/index.ts", import.meta.url).href);
62028
+ if (existsSync20(source)) {
61876
62029
  return source;
61877
62030
  }
61878
- throw new ScoutCliError("Could not find Scout control-plane web server entry. Rebuild @openscout/scout or run from the OpenScout repository.");
62031
+ const legacySource = fileURLToPath9(new URL("../../server/control-plane-index.ts", import.meta.url).href);
62032
+ if (existsSync20(legacySource)) {
62033
+ return legacySource;
62034
+ }
62035
+ throw new ScoutCliError("Could not find Scout web server entry. Rebuild @openscout/scout or run from the OpenScout repository.");
61879
62036
  }
61880
62037
  function parseServerFlags(args) {
61881
62038
  const env = {};
@@ -61949,7 +62106,7 @@ function resolveBundledStaticClientRoot(entry, _mode) {
61949
62106
  const entryDir = dirname14(entry);
61950
62107
  const clientDirectory = join28(entryDir, "client");
61951
62108
  const indexPath = join28(clientDirectory, "index.html");
61952
- return existsSync19(indexPath) ? clientDirectory : null;
62109
+ return existsSync20(indexPath) ? clientDirectory : null;
61953
62110
  }
61954
62111
  function buildMergedServerEnv(entry, mode, flagEnv) {
61955
62112
  const bundledStaticClientRoot = resolveBundledStaticClientRoot(entry, mode);
@@ -61975,7 +62132,7 @@ function parseServerSelection(args) {
61975
62132
  action: "start",
61976
62133
  flagArgs: args.slice(1),
61977
62134
  entry: resolveScoutControlPlaneWebServerEntry(),
61978
- mode: "full"
62135
+ mode: "openscout-web"
61979
62136
  };
61980
62137
  }
61981
62138
  if (args[0] === "open") {
@@ -61983,7 +62140,7 @@ function parseServerSelection(args) {
61983
62140
  action: "open",
61984
62141
  flagArgs: args.slice(1),
61985
62142
  entry: resolveScoutControlPlaneWebServerEntry(),
61986
- mode: "full"
62143
+ mode: "openscout-web"
61987
62144
  };
61988
62145
  }
61989
62146
  if (args[0] === "control-plane") {
@@ -61992,7 +62149,7 @@ function parseServerSelection(args) {
61992
62149
  action: sub,
61993
62150
  flagArgs: args.slice(2),
61994
62151
  entry: resolveScoutControlPlaneWebServerEntry(),
61995
- mode: "control-plane"
62152
+ mode: "openscout-web"
61996
62153
  };
61997
62154
  }
61998
62155
  throw new ScoutCliError(`unknown subcommand: ${args[0]} (try: scout server open)`);
@@ -62028,7 +62185,7 @@ function resolveExpectedCurrentDirectory(env) {
62028
62185
  return resolve14(env.OPENSCOUT_SETUP_CWD?.trim() || process.cwd());
62029
62186
  }
62030
62187
  function renderModeLabel(mode) {
62031
- return mode === "control-plane" ? "Scout control plane" : "Scout";
62188
+ return "Scout web";
62032
62189
  }
62033
62190
  function renderSurfaceLabel(surface) {
62034
62191
  switch (surface) {
@@ -62036,14 +62193,13 @@ function renderSurfaceLabel(surface) {
62036
62193
  return "control-plane";
62037
62194
  case "openscout-web":
62038
62195
  return "@openscout/web";
62039
- case "full":
62040
- default:
62041
- return "full";
62042
62196
  }
62043
62197
  }
62044
62198
  function renderServerOpenResult(result) {
62045
- const prefix = result.mode === "control-plane" ? "Opened Scout control plane" : "Opened Scout";
62046
- return `${prefix} at ${result.url}${result.reusedExistingServer ? "" : " (started server)"}`;
62199
+ return `Opened Scout web at ${result.url}${result.reusedExistingServer ? "" : " (started server)"}`;
62200
+ }
62201
+ function isCurrentScoutWebSurface(surface) {
62202
+ return surface === "openscout-web" || surface === "control-plane";
62047
62203
  }
62048
62204
  function healthUrlForPort(port) {
62049
62205
  return new URL(`/api/health`, `http://127.0.0.1:${port}`);
@@ -62071,7 +62227,7 @@ async function probeScoutServer(port) {
62071
62227
  statusCode: response.status
62072
62228
  };
62073
62229
  }
62074
- if (body.ok === true && (body.surface === "full" || body.surface === "control-plane" || body.surface === "openscout-web") && typeof body.currentDirectory === "string") {
62230
+ if (body.ok === true && (body.surface === "control-plane" || body.surface === "openscout-web") && typeof body.currentDirectory === "string") {
62075
62231
  return {
62076
62232
  status: "healthy",
62077
62233
  health: {
@@ -62150,7 +62306,7 @@ async function waitForScoutServer(port, mode, expectedCurrentDirectory) {
62150
62306
  const probe = await probeScoutServer(port);
62151
62307
  if (probe.status === "healthy") {
62152
62308
  const actualCurrentDirectory = resolve14(probe.health.currentDirectory);
62153
- if (probe.health.surface !== mode) {
62309
+ if (!isCurrentScoutWebSurface(probe.health.surface)) {
62154
62310
  throw new ScoutCliError(`port ${port} is serving Scout ${renderSurfaceLabel(probe.health.surface)}, not ${renderModeLabel(mode)}.`);
62155
62311
  }
62156
62312
  if (actualCurrentDirectory !== expectedCurrentDirectory) {
@@ -62172,7 +62328,7 @@ async function openScoutServer(options) {
62172
62328
  const probe = await probeScoutServer(port);
62173
62329
  if (probe.status === "healthy") {
62174
62330
  const actualCurrentDirectory = resolve14(probe.health.currentDirectory);
62175
- if (probe.health.surface !== options.mode) {
62331
+ if (!isCurrentScoutWebSurface(probe.health.surface)) {
62176
62332
  throw new ScoutCliError(`port ${port} is already serving Scout ${renderSurfaceLabel(probe.health.surface)}, not ${renderModeLabel(options.mode)}.`);
62177
62333
  }
62178
62334
  if (actualCurrentDirectory !== expectedCurrentDirectory) {
@@ -62370,7 +62526,7 @@ import { EventEmitter as EventEmitter2 } from "events";
62370
62526
  import { resolve as resolve15, dirname as dirname15 } from "path";
62371
62527
  import { fileURLToPath as fileURLToPath10 } from "url";
62372
62528
  import { resolve as resolve22, isAbsolute as isAbsolute5, parse as parse7 } from "path";
62373
- import { existsSync as existsSync20 } from "fs";
62529
+ import { existsSync as existsSync21 } from "fs";
62374
62530
  import { basename as basename11, join as join29 } from "path";
62375
62531
  import os from "os";
62376
62532
  import path2 from "path";
@@ -76584,7 +76740,7 @@ var init_index_vy1rm1x3 = __esm(async () => {
76584
76740
  worker_path = this.options.workerPath;
76585
76741
  } else {
76586
76742
  worker_path = new URL("./parser.worker.js", import.meta.url).href;
76587
- if (!existsSync20(resolve22(import.meta.dirname, "parser.worker.js"))) {
76743
+ if (!existsSync21(resolve22(import.meta.dirname, "parser.worker.js"))) {
76588
76744
  worker_path = new URL("./parser.worker.ts", import.meta.url).href;
76589
76745
  }
76590
76746
  }
@@ -123658,7 +123814,7 @@ var exports_up = {};
123658
123814
  __export(exports_up, {
123659
123815
  runUpCommand: () => runUpCommand
123660
123816
  });
123661
- import { existsSync as existsSync21 } from "fs";
123817
+ import { existsSync as existsSync23 } from "fs";
123662
123818
  import { resolve as resolve17 } from "path";
123663
123819
  function looksLikePath(value) {
123664
123820
  return value.includes("/") || value.startsWith(".") || value.startsWith("~");
@@ -123707,7 +123863,7 @@ async function runUpCommand(context, args) {
123707
123863
  throw new ScoutCliError("usage: scout up <name|path> [--name <alias>] [--harness <claude|codex>]");
123708
123864
  }
123709
123865
  let projectPath;
123710
- if (looksLikePath(target) || existsSync21(resolve17(target))) {
123866
+ if (looksLikePath(target) || existsSync23(resolve17(target))) {
123711
123867
  projectPath = resolve17(target);
123712
123868
  } else {
123713
123869
  const resolved = await resolveLocalAgentByName(target);
@@ -123827,7 +123983,7 @@ var init_whoami = __esm(async () => {
123827
123983
  });
123828
123984
 
123829
123985
  // ../../apps/desktop/src/cli/main.ts
123830
- import { existsSync as existsSync23, readFileSync as readFileSync14, writeFileSync as writeFileSync9, statSync as statSync5, mkdirSync as mkdirSync12 } from "fs";
123986
+ import { existsSync as existsSync25, readFileSync as readFileSync15, writeFileSync as writeFileSync9, statSync as statSync5, mkdirSync as mkdirSync12 } from "fs";
123831
123987
  import { join as join32 } from "path";
123832
123988
  import { spawnSync as spawnSync3 } from "child_process";
123833
123989
  import { homedir as homedir23 } from "os";
@@ -124091,7 +124247,7 @@ function getScoutBinPath() {
124091
124247
  if (_scoutBinPath)
124092
124248
  return _scoutBinPath;
124093
124249
  _scoutBinPath = join32(homedir23(), ".bun", "bin", "scout");
124094
- if (!existsSync23(_scoutBinPath)) {
124250
+ if (!existsSync25(_scoutBinPath)) {
124095
124251
  _scoutBinPath = spawnSync3("which", ["scout"], { encoding: "utf8" }).stdout.trim();
124096
124252
  }
124097
124253
  return _scoutBinPath;
@@ -124101,7 +124257,7 @@ async function ensureBrokerUptodate() {
124101
124257
  const mtime = statSync5(getScoutBinPath()).mtimeMs;
124102
124258
  const checkpointDir = join32(homedir23(), ".scout");
124103
124259
  const mtimePath = join32(checkpointDir, "cli-mtime");
124104
- const lastMtime = existsSync23(mtimePath) ? Number(readFileSync14(mtimePath, "utf8").trim()) : 0;
124260
+ const lastMtime = existsSync25(mtimePath) ? Number(readFileSync15(mtimePath, "utf8").trim()) : 0;
124105
124261
  if (mtime > lastMtime) {
124106
124262
  const uid = process.getuid();
124107
124263
  const plistPath = join32(homedir23(), "Library", "LaunchAgents", "dev.openscout.broker.plist");
@@ -124110,7 +124266,7 @@ async function ensureBrokerUptodate() {
124110
124266
  spawnSync3("launchctl", ["bootstrap", `gui/${uid}`, plistPath], { stdio: "ignore" });
124111
124267
  await new Promise((resolve18) => setTimeout(resolve18, 2000));
124112
124268
  }
124113
- if (!existsSync23(checkpointDir)) {
124269
+ if (!existsSync25(checkpointDir)) {
124114
124270
  mkdirSync12(checkpointDir, { recursive: true });
124115
124271
  }
124116
124272
  writeFileSync9(mtimePath, String(Math.floor(mtime)), { encoding: "utf8", flag: "w" });