@openscout/scout 0.2.47 → 0.2.48

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
@@ -2682,31 +2682,6 @@ var init_user_project_hints = __esm(() => {
2682
2682
  });
2683
2683
 
2684
2684
  // ../runtime/src/setup.ts
2685
- var exports_setup = {};
2686
- __export(exports_setup, {
2687
- writeRelayAgentOverrides: () => writeRelayAgentOverrides,
2688
- writeProjectConfig: () => writeProjectConfig,
2689
- writeOpenScoutSettings: () => writeOpenScoutSettings,
2690
- resolveRelayAgentConfig: () => resolveRelayAgentConfig,
2691
- readRelayAgentOverrides: () => readRelayAgentOverrides,
2692
- readProjectConfig: () => readProjectConfig,
2693
- readOpenScoutSettings: () => readOpenScoutSettings,
2694
- primaryDirectConversationIdForAgent: () => primaryDirectConversationIdForAgent,
2695
- loadResolvedRelayAgents: () => loadResolvedRelayAgents,
2696
- installScoutSkillToHarnesses: () => installScoutSkillToHarnesses,
2697
- initializeOpenScoutSetup: () => initializeOpenScoutSetup,
2698
- findNearestProjectRoot: () => findNearestProjectRoot,
2699
- ensureScoutRelayAgentConfigured: () => ensureScoutRelayAgentConfigured,
2700
- ensureRelayAgentConfigured: () => ensureRelayAgentConfigured,
2701
- ensureProjectConfigForDirectory: () => ensureProjectConfigForDirectory,
2702
- detectPreferredHarness: () => detectPreferredHarness,
2703
- clearGitBranchCache: () => clearGitBranchCache,
2704
- buildRelayAgentInstance: () => buildRelayAgentInstance,
2705
- SCOUT_PRIMARY_CONVERSATION_ID: () => SCOUT_PRIMARY_CONVERSATION_ID,
2706
- SCOUT_AGENT_ID: () => SCOUT_AGENT_ID,
2707
- MANAGED_AGENT_HARNESSES: () => MANAGED_AGENT_HARNESSES,
2708
- DEFAULT_OPERATOR_NAME: () => DEFAULT_OPERATOR_NAME
2709
- });
2710
2685
  import { execFileSync as execFileSync2 } from "child_process";
2711
2686
  import { existsSync as existsSync3, readFileSync } from "fs";
2712
2687
  import { access, mkdir as mkdir2, readdir as readdir2, readFile as readFile3, realpath, rm, stat as stat2, writeFile as writeFile2 } from "fs/promises";
@@ -2885,13 +2860,6 @@ function normalizeTelegramConversationId(value) {
2885
2860
  }
2886
2861
  return normalized;
2887
2862
  }
2888
- function primaryDirectConversationIdForAgent(agentId) {
2889
- const normalizedAgentId = normalizeAgentId(agentId);
2890
- if (normalizedAgentId === SCOUT_AGENT_ID) {
2891
- return SCOUT_PRIMARY_CONVERSATION_ID;
2892
- }
2893
- return `dm.operator.${normalizedAgentId}`;
2894
- }
2895
2863
  function resolveNodeQualifier() {
2896
2864
  const fromEnv = process.env.OPENSCOUT_NODE_QUALIFIER?.trim();
2897
2865
  if (fromEnv) {
@@ -2937,13 +2905,6 @@ function detectGitBranch(projectRoot) {
2937
2905
  gitBranchCache.set(projectRoot, { branch, expiresAt: now + GIT_BRANCH_CACHE_TTL_MS });
2938
2906
  return branch;
2939
2907
  }
2940
- function clearGitBranchCache(projectRoot) {
2941
- if (projectRoot) {
2942
- gitBranchCache.delete(projectRoot);
2943
- } else {
2944
- gitBranchCache.clear();
2945
- }
2946
- }
2947
2908
  function resolveWorkspaceQualifier(projectRoot) {
2948
2909
  const normalizedProjectRoot = normalizePath(projectRoot);
2949
2910
  const branch = detectGitBranch(normalizedProjectRoot);
@@ -4430,52 +4391,6 @@ async function ensureRelayAgentConfigured(value, options = {}) {
4430
4391
  registrationKind: "configured"
4431
4392
  };
4432
4393
  }
4433
- async function ensureScoutRelayAgentConfigured(options = {}) {
4434
- const settings = await readOpenScoutSettings({ currentDirectory: options.currentDirectory });
4435
- const overrides = await readRelayAgentOverrides();
4436
- const resolvedProjectRoot = options.projectRoot ? normalizePath(options.projectRoot) : options.currentDirectory ? await findNearestProjectRoot(options.currentDirectory) ?? normalizePath(options.currentDirectory) : normalizePath(process.cwd());
4437
- const qualifiedAgentId = buildRelayAgentInstance(SCOUT_AGENT_ID, resolvedProjectRoot).id;
4438
- const existing = overrides[qualifiedAgentId] ?? overrides[SCOUT_AGENT_ID];
4439
- const nextOverride = {
4440
- ...existing,
4441
- agentId: qualifiedAgentId,
4442
- definitionId: SCOUT_AGENT_ID,
4443
- displayName: "Scout",
4444
- projectName: "OpenScout",
4445
- projectRoot: resolvedProjectRoot,
4446
- projectConfigPath: existing?.projectConfigPath ? normalizePath(existing.projectConfigPath) : null,
4447
- source: "manual",
4448
- startedAt: existing?.startedAt ?? nowSeconds(),
4449
- systemPrompt: existing?.systemPrompt?.trim() || undefined,
4450
- capabilities: normalizeCapabilities(existing?.capabilities),
4451
- defaultHarness: "claude",
4452
- harnessProfiles: buildHarnessProfiles({
4453
- projectRoot: resolvedProjectRoot,
4454
- sessionKey: qualifiedAgentId,
4455
- sessionPrefix: settings.agents.sessionPrefix,
4456
- defaultHarness: "claude",
4457
- profiles: existing?.harnessProfiles,
4458
- runtime: existing?.runtime,
4459
- launchArgs: normalizeLaunchArgs(existing?.launchArgs)
4460
- }),
4461
- runtime: {
4462
- cwd: resolvedProjectRoot,
4463
- harness: "claude",
4464
- transport: "claude_stream_json",
4465
- sessionId: normalizeTmuxSessionName(existing?.runtime?.sessionId, `${SCOUT_AGENT_ID}-claude`, settings.agents.sessionPrefix),
4466
- wakePolicy: "on_demand"
4467
- }
4468
- };
4469
- nextOverride.launchArgs = nextOverride.harnessProfiles?.claude?.launchArgs ?? [];
4470
- if (overrides[SCOUT_AGENT_ID]) {
4471
- delete overrides[SCOUT_AGENT_ID];
4472
- }
4473
- if (JSON.stringify(overrides[qualifiedAgentId]) !== JSON.stringify(nextOverride)) {
4474
- overrides[qualifiedAgentId] = nextOverride;
4475
- await writeRelayAgentOverrides(overrides);
4476
- }
4477
- return nextOverride;
4478
- }
4479
4394
  async function initializeOpenScoutSetup(options = {}) {
4480
4395
  return loadResolvedRelayAgents({
4481
4396
  currentDirectory: options.currentDirectory,
@@ -4639,418 +4554,6 @@ async function readOptionalFile(filePath) {
4639
4554
  return null;
4640
4555
  }
4641
4556
  }
4642
- function parseJsonObject(value) {
4643
- const trimmed = value?.trim();
4644
- if (!trimmed) {
4645
- return {};
4646
- }
4647
- try {
4648
- const parsed = JSON.parse(trimmed);
4649
- return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
4650
- } catch {
4651
- return {};
4652
- }
4653
- }
4654
- function appendActionOutput(blockState, output) {
4655
- if (!blockState || blockState.block.type !== "action" || !output) {
4656
- return;
4657
- }
4658
- const actionBlock = blockState.block;
4659
- actionBlock.action.output += output;
4660
- }
4661
- function updateBlockCompletion(blockState, completed) {
4662
- if (!blockState) {
4663
- return;
4664
- }
4665
- blockState.status = completed ? "completed" : "streaming";
4666
- blockState.block.status = completed ? "completed" : "streaming";
4667
- }
4668
- function parseQuestionAnswer(value) {
4669
- if (Array.isArray(value)) {
4670
- return value.map((entry) => typeof entry === "string" ? entry.trim() : String(entry).trim()).filter(Boolean);
4671
- }
4672
- if (typeof value === "string") {
4673
- return value.split(",").map((entry) => entry.trim()).filter(Boolean);
4674
- }
4675
- if (value == null) {
4676
- return [];
4677
- }
4678
- return [String(value)];
4679
- }
4680
- function isClaudeSessionGlobalEvent(event) {
4681
- return event.type === "system" && event.subtype === "init";
4682
- }
4683
- function stringifyToolResultContent(value) {
4684
- if (typeof value === "string") {
4685
- return value;
4686
- }
4687
- if (Array.isArray(value)) {
4688
- return value.map((entry) => stringifyToolResultContent(entry)).filter(Boolean).join(`
4689
- `);
4690
- }
4691
- if (value == null) {
4692
- return "";
4693
- }
4694
- try {
4695
- return JSON.stringify(value);
4696
- } catch {
4697
- return String(value);
4698
- }
4699
- }
4700
- function buildClaudeAction(toolName, toolUseId, input) {
4701
- if (toolName === "Edit" || toolName === "Write" || toolName === "MultiEdit") {
4702
- return {
4703
- kind: "file_change",
4704
- path: typeof input.file_path === "string" ? input.file_path : typeof input.path === "string" ? input.path : "",
4705
- diff: "",
4706
- status: "running",
4707
- output: ""
4708
- };
4709
- }
4710
- if (toolName === "Bash") {
4711
- return {
4712
- kind: "command",
4713
- command: typeof input.command === "string" ? input.command : "",
4714
- status: "running",
4715
- output: ""
4716
- };
4717
- }
4718
- if (toolName === "Agent") {
4719
- return {
4720
- kind: "subagent",
4721
- agentId: toolUseId,
4722
- agentName: typeof input.description === "string" ? input.description : undefined,
4723
- prompt: typeof input.prompt === "string" ? input.prompt : undefined,
4724
- status: "running",
4725
- output: ""
4726
- };
4727
- }
4728
- return {
4729
- kind: "tool_call",
4730
- toolName,
4731
- toolCallId: toolUseId,
4732
- input,
4733
- status: "running",
4734
- output: ""
4735
- };
4736
- }
4737
- function buildClaudeStreamJsonSessionSnapshot(raw, options, targetClaudeSessionId) {
4738
- const lines = raw.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
4739
- let resolvedSessionId = targetClaudeSessionId?.trim() || null;
4740
- if (!resolvedSessionId) {
4741
- for (const line of lines) {
4742
- try {
4743
- const event = JSON.parse(line);
4744
- const nextSessionId = typeof event.session_id === "string" ? event.session_id : typeof event.sessionId === "string" ? event.sessionId : null;
4745
- if (event.type === "system" && event.subtype === "init" && nextSessionId) {
4746
- resolvedSessionId = nextSessionId;
4747
- } else if (!resolvedSessionId && nextSessionId) {
4748
- resolvedSessionId = nextSessionId;
4749
- }
4750
- } catch {}
4751
- }
4752
- }
4753
- const snapshot = {
4754
- session: {
4755
- id: options.sessionId,
4756
- name: options.agentName,
4757
- adapterType: "claude_stream_json",
4758
- status: "idle",
4759
- cwd: options.cwd,
4760
- providerMeta: resolvedSessionId ? { transportSessionId: resolvedSessionId } : undefined
4761
- },
4762
- turns: []
4763
- };
4764
- let currentTurn = null;
4765
- const blockById = new Map;
4766
- let activeContentBlocks = new Map;
4767
- let pendingToolBlocks = new Map;
4768
- const startTurn = () => {
4769
- const turn = {
4770
- id: `${options.sessionId}:turn:${snapshot.turns.length + 1}`,
4771
- status: "streaming",
4772
- blocks: [],
4773
- startedAt: Date.now(),
4774
- nextBlockIndex: 0,
4775
- nextMessageIndex: 0
4776
- };
4777
- snapshot.turns.push(turn);
4778
- snapshot.currentTurnId = turn.id;
4779
- currentTurn = turn;
4780
- activeContentBlocks = new Map;
4781
- pendingToolBlocks = new Map;
4782
- snapshot.session.status = "active";
4783
- return turn;
4784
- };
4785
- const ensureTurn = () => currentTurn ?? startTurn();
4786
- const startTextualBlock = (type, index, initialText = "") => {
4787
- const turn = ensureTurn();
4788
- const blockId = `${turn.id}:m${turn.nextMessageIndex}:i${index}`;
4789
- const block = type === "text" ? {
4790
- id: blockId,
4791
- turnId: turn.id,
4792
- index: turn.nextBlockIndex++,
4793
- type: "text",
4794
- text: initialText,
4795
- status: "streaming"
4796
- } : {
4797
- id: blockId,
4798
- turnId: turn.id,
4799
- index: turn.nextBlockIndex++,
4800
- type: "reasoning",
4801
- text: initialText,
4802
- status: "streaming"
4803
- };
4804
- const blockState = {
4805
- block,
4806
- status: "streaming"
4807
- };
4808
- turn.blocks.push(blockState);
4809
- blockById.set(blockId, blockState);
4810
- activeContentBlocks.set(index, blockState);
4811
- return blockState;
4812
- };
4813
- const finalizeCurrentTurn = (status) => {
4814
- if (!currentTurn) {
4815
- return;
4816
- }
4817
- for (const blockState of activeContentBlocks.values()) {
4818
- updateBlockCompletion(blockState, true);
4819
- }
4820
- activeContentBlocks.clear();
4821
- currentTurn.status = status;
4822
- currentTurn.endedAt = Date.now();
4823
- currentTurn = null;
4824
- snapshot.currentTurnId = undefined;
4825
- snapshot.session.status = status === "error" ? "error" : "idle";
4826
- };
4827
- for (const line of lines) {
4828
- let event;
4829
- try {
4830
- event = JSON.parse(line);
4831
- } catch {
4832
- continue;
4833
- }
4834
- const eventSessionId = typeof event.session_id === "string" ? event.session_id : typeof event.sessionId === "string" ? event.sessionId : null;
4835
- if (resolvedSessionId) {
4836
- if (eventSessionId && eventSessionId !== resolvedSessionId) {
4837
- continue;
4838
- }
4839
- if (!eventSessionId && !isClaudeSessionGlobalEvent(event)) {
4840
- continue;
4841
- }
4842
- }
4843
- if (event.type === "system" && event.subtype === "init") {
4844
- if (typeof event.model === "string" && event.model.trim()) {
4845
- snapshot.session.model = event.model;
4846
- }
4847
- if (typeof event.cwd === "string" && event.cwd.trim()) {
4848
- snapshot.session.cwd = event.cwd;
4849
- }
4850
- snapshot.session.status = currentTurn ? "active" : "idle";
4851
- continue;
4852
- }
4853
- if (event.type === "stream_event") {
4854
- const streamEvent = event.event;
4855
- const streamEventType = typeof streamEvent?.type === "string" ? streamEvent.type : "";
4856
- if (streamEventType === "message_start") {
4857
- const turn = ensureTurn();
4858
- turn.nextMessageIndex += 1;
4859
- activeContentBlocks.clear();
4860
- pendingToolBlocks.clear();
4861
- snapshot.session.status = "active";
4862
- continue;
4863
- }
4864
- if (streamEventType === "content_block_start") {
4865
- const turn = ensureTurn();
4866
- const blockIndex = typeof streamEvent?.index === "number" ? streamEvent.index : 0;
4867
- const contentBlock = streamEvent?.content_block;
4868
- const contentType = typeof contentBlock?.type === "string" ? contentBlock.type : "";
4869
- if (contentType === "thinking") {
4870
- startTextualBlock("reasoning", blockIndex, typeof contentBlock?.thinking === "string" ? contentBlock.thinking : "");
4871
- } else if (contentType === "text") {
4872
- startTextualBlock("text", blockIndex, typeof contentBlock?.text === "string" ? contentBlock.text : "");
4873
- } else if (contentType === "tool_use") {
4874
- pendingToolBlocks.set(blockIndex, {
4875
- toolUseId: typeof contentBlock?.id === "string" ? contentBlock.id : `${turn.id}:tool:${blockIndex}`,
4876
- toolName: typeof contentBlock?.name === "string" ? contentBlock.name : "unknown",
4877
- input: contentBlock?.input && typeof contentBlock.input === "object" && !Array.isArray(contentBlock.input) ? contentBlock.input : {},
4878
- inputJson: "",
4879
- blockIndex: turn.nextBlockIndex++
4880
- });
4881
- }
4882
- continue;
4883
- }
4884
- if (streamEventType === "content_block_delta") {
4885
- const blockIndex = typeof streamEvent?.index === "number" ? streamEvent.index : 0;
4886
- const delta = streamEvent?.delta;
4887
- const deltaType = typeof delta?.type === "string" ? delta.type : "";
4888
- if (deltaType === "text_delta") {
4889
- const blockState = activeContentBlocks.get(blockIndex);
4890
- if (blockState?.block.type === "text" && typeof delta?.text === "string") {
4891
- blockState.block.text += delta.text;
4892
- }
4893
- continue;
4894
- }
4895
- if (deltaType === "thinking_delta") {
4896
- const blockState = activeContentBlocks.get(blockIndex);
4897
- if (blockState?.block.type === "reasoning" && typeof delta?.thinking === "string") {
4898
- blockState.block.text += delta.thinking;
4899
- }
4900
- continue;
4901
- }
4902
- if (deltaType === "input_json_delta") {
4903
- const pending = pendingToolBlocks.get(blockIndex);
4904
- if (pending && typeof delta?.partial_json === "string") {
4905
- pending.inputJson += delta.partial_json;
4906
- }
4907
- }
4908
- continue;
4909
- }
4910
- if (streamEventType === "content_block_stop") {
4911
- const blockIndex = typeof streamEvent?.index === "number" ? streamEvent.index : 0;
4912
- const blockState = activeContentBlocks.get(blockIndex);
4913
- if (blockState) {
4914
- updateBlockCompletion(blockState, true);
4915
- activeContentBlocks.delete(blockIndex);
4916
- continue;
4917
- }
4918
- const pendingTool = pendingToolBlocks.get(blockIndex);
4919
- if (!pendingTool) {
4920
- continue;
4921
- }
4922
- const turn = ensureTurn();
4923
- const parsedInput = {
4924
- ...pendingTool.input,
4925
- ...parseJsonObject(pendingTool.inputJson)
4926
- };
4927
- if (pendingTool.toolName === "AskUserQuestion") {
4928
- const questions = Array.isArray(parsedInput.questions) ? parsedInput.questions : [];
4929
- const firstQuestion = questions[0] ?? {};
4930
- const block = {
4931
- id: pendingTool.toolUseId,
4932
- turnId: turn.id,
4933
- index: pendingTool.blockIndex,
4934
- type: "question",
4935
- header: typeof firstQuestion.header === "string" ? firstQuestion.header : undefined,
4936
- question: typeof firstQuestion.question === "string" ? firstQuestion.question : "",
4937
- options: Array.isArray(firstQuestion.options) ? firstQuestion.options.map((option) => {
4938
- if (typeof option === "string") {
4939
- return { label: option };
4940
- }
4941
- const optionRecord = option;
4942
- return {
4943
- label: typeof optionRecord.label === "string" ? optionRecord.label : String(option),
4944
- description: typeof optionRecord.description === "string" ? optionRecord.description : undefined
4945
- };
4946
- }) : [],
4947
- multiSelect: Boolean(firstQuestion.multiSelect),
4948
- questionStatus: "awaiting_answer",
4949
- status: "streaming"
4950
- };
4951
- const nextBlockState = { block, status: "streaming" };
4952
- turn.blocks.push(nextBlockState);
4953
- blockById.set(block.id, nextBlockState);
4954
- } else {
4955
- const block = {
4956
- id: pendingTool.toolUseId,
4957
- turnId: turn.id,
4958
- index: pendingTool.blockIndex,
4959
- type: "action",
4960
- action: buildClaudeAction(pendingTool.toolName, pendingTool.toolUseId, parsedInput),
4961
- status: "streaming"
4962
- };
4963
- const nextBlockState = { block, status: "streaming" };
4964
- turn.blocks.push(nextBlockState);
4965
- blockById.set(block.id, nextBlockState);
4966
- }
4967
- pendingToolBlocks.delete(blockIndex);
4968
- }
4969
- continue;
4970
- }
4971
- if (event.type === "user") {
4972
- const message = event.message;
4973
- const content = Array.isArray(message?.content) ? message.content : [];
4974
- for (const entry of content) {
4975
- const result = entry;
4976
- if (result.type !== "tool_result" || typeof result.tool_use_id !== "string") {
4977
- continue;
4978
- }
4979
- const blockState = blockById.get(result.tool_use_id);
4980
- if (!blockState) {
4981
- continue;
4982
- }
4983
- if (blockState.block.type === "question") {
4984
- const questionBlock = blockState.block;
4985
- questionBlock.questionStatus = result.is_error ? "denied" : "answered";
4986
- const answer = parseQuestionAnswer(result.content);
4987
- questionBlock.answer = answer.length > 0 ? answer : undefined;
4988
- updateBlockCompletion(blockState, true);
4989
- continue;
4990
- }
4991
- appendActionOutput(blockState, stringifyToolResultContent(result.content));
4992
- if (blockState.block.type === "action") {
4993
- blockState.block.action.status = result.is_error ? "failed" : "completed";
4994
- }
4995
- updateBlockCompletion(blockState, true);
4996
- }
4997
- continue;
4998
- }
4999
- if (event.type === "result") {
5000
- const permissionDenials = Array.isArray(event.permission_denials) ? event.permission_denials : [];
5001
- for (const denial of permissionDenials) {
5002
- if (denial.tool_name !== "AskUserQuestion") {
5003
- continue;
5004
- }
5005
- const toolUseId = typeof denial.tool_use_id === "string" ? denial.tool_use_id : null;
5006
- const blockState = toolUseId ? blockById.get(toolUseId) : undefined;
5007
- if (blockState?.block.type === "question") {
5008
- blockState.block.questionStatus = "denied";
5009
- updateBlockCompletion(blockState, true);
5010
- continue;
5011
- }
5012
- const input = denial.tool_input && typeof denial.tool_input === "object" && !Array.isArray(denial.tool_input) ? denial.tool_input : {};
5013
- const questions = Array.isArray(input.questions) ? input.questions : [];
5014
- const firstQuestion = questions[0] ?? {};
5015
- const turn = ensureTurn();
5016
- const block = {
5017
- id: toolUseId ?? `${turn.id}:denied:${turn.nextBlockIndex}`,
5018
- turnId: turn.id,
5019
- index: turn.nextBlockIndex++,
5020
- type: "question",
5021
- header: typeof firstQuestion.header === "string" ? firstQuestion.header : undefined,
5022
- question: typeof firstQuestion.question === "string" ? firstQuestion.question : "",
5023
- options: Array.isArray(firstQuestion.options) ? firstQuestion.options.map((option) => {
5024
- if (typeof option === "string") {
5025
- return { label: option };
5026
- }
5027
- const optionRecord = option;
5028
- return {
5029
- label: typeof optionRecord.label === "string" ? optionRecord.label : String(option),
5030
- description: typeof optionRecord.description === "string" ? optionRecord.description : undefined
5031
- };
5032
- }) : [],
5033
- multiSelect: Boolean(firstQuestion.multiSelect),
5034
- questionStatus: "denied",
5035
- status: "completed"
5036
- };
5037
- const deniedBlock = { block, status: "completed" };
5038
- turn.blocks.push(deniedBlock);
5039
- blockById.set(block.id, deniedBlock);
5040
- }
5041
- finalizeCurrentTurn(event.is_error ? "error" : "completed");
5042
- continue;
5043
- }
5044
- if (event.type === "error") {
5045
- finalizeCurrentTurn("error");
5046
- }
5047
- }
5048
- if (!resolvedSessionId && snapshot.turns.length === 0) {
5049
- return null;
5050
- }
5051
- snapshot.session.status = currentTurn ? "active" : snapshot.session.status;
5052
- return snapshot;
5053
- }
5054
4557
 
5055
4558
  class ClaudeStreamJsonSession {
5056
4559
  options;
@@ -5333,35 +4836,10 @@ async function ensureClaudeStreamJsonAgentOnline(options) {
5333
4836
  session.update(options);
5334
4837
  return session.ensureOnline();
5335
4838
  }
5336
- async function invokeClaudeStreamJsonAgent(options) {
5337
- const session = getOrCreateSession(options);
5338
- session.update(options);
5339
- return session.invoke(options.prompt, options.timeoutMs);
5340
- }
5341
4839
  function isClaudeStreamJsonAgentAlive(options) {
5342
4840
  const session = sessions.get(sessionKey(options));
5343
4841
  return Boolean(session?.isAlive());
5344
4842
  }
5345
- async function answerClaudeStreamJsonQuestion(options, input) {
5346
- const session = sessions.get(sessionKey(options));
5347
- if (!session) {
5348
- throw new Error(`Claude stream-json session for ${options.agentName} is not running.`);
5349
- }
5350
- session.update(options);
5351
- await session.answerQuestion(input.blockId, input.answer);
5352
- }
5353
- async function getClaudeStreamJsonAgentSnapshot(options) {
5354
- const stdoutLogPath = join5(options.logsDirectory, "stdout.log");
5355
- const sessionStatePath = join5(options.runtimeDirectory, "claude-session-id.txt");
5356
- const [rawLog, persistedSessionId] = await Promise.all([
5357
- readOptionalFile(stdoutLogPath),
5358
- readOptionalFile(sessionStatePath)
5359
- ]);
5360
- if (!rawLog) {
5361
- return null;
5362
- }
5363
- return buildClaudeStreamJsonSessionSnapshot(rawLog, options, persistedSessionId);
5364
- }
5365
4843
  async function shutdownClaudeStreamJsonAgent(options, shutdownOptions = {}) {
5366
4844
  const key = sessionKey(options);
5367
4845
  const session = sessions.get(key);
@@ -5383,11 +4861,6 @@ var init_claude_stream_json = __esm(() => {
5383
4861
  import { spawn as spawn2 } from "child_process";
5384
4862
  import { access as access2, appendFile as appendFile2, constants, mkdir as mkdir4, readFile as readFile5, rm as rm3, writeFile as writeFile4 } from "fs/promises";
5385
4863
  import { delimiter, join as join6 } from "path";
5386
- function isCodexThreadGlobalMessage(message) {
5387
- const result = message.result;
5388
- const thread = result?.thread;
5389
- return typeof thread?.id === "string";
5390
- }
5391
4864
  function sessionKey2(options) {
5392
4865
  return `${options.agentName}:${options.sessionId}`;
5393
4866
  }
@@ -5454,14 +4927,6 @@ function parseJsonLine(line) {
5454
4927
  return null;
5455
4928
  }
5456
4929
  }
5457
- function parseJsonRecord(line) {
5458
- try {
5459
- const value = JSON.parse(line);
5460
- return value && typeof value === "object" && !Array.isArray(value) ? value : null;
5461
- } catch {
5462
- return null;
5463
- }
5464
- }
5465
4930
  function errorMessage2(error) {
5466
4931
  if (error instanceof Error) {
5467
4932
  return error.message;
@@ -5500,687 +4965,6 @@ async function readOptionalFile2(filePath) {
5500
4965
  return null;
5501
4966
  }
5502
4967
  }
5503
- async function readOptionalJsonRecord(filePath) {
5504
- const raw = await readOptionalFile2(filePath);
5505
- return raw ? parseJsonRecord(raw) : null;
5506
- }
5507
- function codexThreadStatusToSessionStatus(status) {
5508
- switch (status) {
5509
- case "active":
5510
- return "active";
5511
- case "idle":
5512
- return "idle";
5513
- case "error":
5514
- return "error";
5515
- default:
5516
- return "connecting";
5517
- }
5518
- }
5519
- function codexTurnStatusToTurnStatus(status) {
5520
- switch (status) {
5521
- case "completed":
5522
- return "completed";
5523
- case "interrupted":
5524
- return "interrupted";
5525
- case "failed":
5526
- return "error";
5527
- default:
5528
- return "streaming";
5529
- }
5530
- }
5531
- function stringifyCodexItem(value) {
5532
- if (typeof value === "string") {
5533
- return value;
5534
- }
5535
- if (value == null) {
5536
- return "";
5537
- }
5538
- try {
5539
- return JSON.stringify(value);
5540
- } catch {
5541
- return String(value);
5542
- }
5543
- }
5544
- function parseCodexTimestamp(value) {
5545
- if (typeof value === "number" && Number.isFinite(value)) {
5546
- return value > 1000000000000 ? value : value * 1000;
5547
- }
5548
- if (typeof value === "string") {
5549
- const parsed = Date.parse(value);
5550
- if (Number.isFinite(parsed)) {
5551
- return parsed;
5552
- }
5553
- }
5554
- return;
5555
- }
5556
- function parseCodexMaybeJson(value) {
5557
- if (typeof value !== "string") {
5558
- return value;
5559
- }
5560
- const trimmed = value.trim();
5561
- if (!trimmed) {
5562
- return value;
5563
- }
5564
- try {
5565
- return JSON.parse(trimmed);
5566
- } catch {
5567
- return value;
5568
- }
5569
- }
5570
- function extractCodexReasoningText(item) {
5571
- const summary = Array.isArray(item.summary) ? item.summary : [];
5572
- const content = Array.isArray(item.content) ? item.content : [];
5573
- const summaryText = summary.map((entry) => {
5574
- if (typeof entry === "string") {
5575
- return entry;
5576
- }
5577
- const record = entry;
5578
- if (typeof record.text === "string") {
5579
- return record.text;
5580
- }
5581
- if (typeof record.summary === "string") {
5582
- return record.summary;
5583
- }
5584
- return "";
5585
- }).filter(Boolean).join(`
5586
- `);
5587
- const contentText = content.map((entry) => {
5588
- if (typeof entry === "string") {
5589
- return entry;
5590
- }
5591
- const record = entry;
5592
- return typeof record.text === "string" ? record.text : "";
5593
- }).filter(Boolean).join(`
5594
- `);
5595
- return [summaryText, contentText].filter(Boolean).join(`
5596
-
5597
- `).trim();
5598
- }
5599
- function extractCodexMessageText(item) {
5600
- const content = Array.isArray(item.content) ? item.content : [];
5601
- return content.map((entry) => {
5602
- if (typeof entry === "string") {
5603
- return entry;
5604
- }
5605
- const record = entry;
5606
- return typeof record.text === "string" ? record.text : "";
5607
- }).filter(Boolean).join(`
5608
-
5609
- `).trim();
5610
- }
5611
- function extractCodexUserMessageText(item) {
5612
- const text = extractCodexMessageText(item);
5613
- if (text) {
5614
- return text;
5615
- }
5616
- return typeof item.text === "string" ? item.text.trim() : "";
5617
- }
5618
- function renderCodexActionOutput(item) {
5619
- if (typeof item.text === "string" && item.text.trim()) {
5620
- return item.text;
5621
- }
5622
- if (item.action !== undefined) {
5623
- return stringifyCodexItem(item.action);
5624
- }
5625
- return stringifyCodexItem(item);
5626
- }
5627
- function buildCodexActionBlock(item, turnId, index) {
5628
- return {
5629
- id: typeof item.id === "string" ? item.id : `${turnId}:action:${index}`,
5630
- turnId,
5631
- index,
5632
- type: "action",
5633
- status: "streaming",
5634
- action: {
5635
- kind: "tool_call",
5636
- toolName: typeof item.type === "string" ? item.type : "unknown",
5637
- toolCallId: typeof item.id === "string" ? item.id : `${turnId}:action:${index}`,
5638
- input: item,
5639
- output: "",
5640
- status: "running"
5641
- }
5642
- };
5643
- }
5644
- function buildCodexRolloutActionBlock(item, turnId, index) {
5645
- const itemType = typeof item.type === "string" ? item.type : "tool_call";
5646
- const toolCallId = typeof item.call_id === "string" ? item.call_id : `${turnId}:action:${index}`;
5647
- const toolName = typeof item.name === "string" ? item.name : itemType === "web_search_call" ? "web_search" : itemType;
5648
- const input = itemType === "function_call" ? parseCodexMaybeJson(item.arguments) : itemType === "custom_tool_call" ? item.input : item;
5649
- return {
5650
- id: toolCallId,
5651
- turnId,
5652
- index,
5653
- type: "action",
5654
- status: "streaming",
5655
- action: {
5656
- kind: "tool_call",
5657
- toolName,
5658
- toolCallId,
5659
- input,
5660
- output: "",
5661
- status: "running"
5662
- }
5663
- };
5664
- }
5665
- function finalizeCodexTurnBlocks(turn, status) {
5666
- for (const blockState of turn.blocks) {
5667
- if (blockState.status === "completed") {
5668
- continue;
5669
- }
5670
- blockState.status = "completed";
5671
- blockState.block.status = "completed";
5672
- if (blockState.block.type === "action") {
5673
- blockState.block.action.status = status === "completed" ? "completed" : "failed";
5674
- }
5675
- }
5676
- }
5677
- function setCodexProviderMeta(snapshot, threadId, threadPath) {
5678
- if (!threadId && !threadPath) {
5679
- return;
5680
- }
5681
- snapshot.session.providerMeta = {
5682
- ...snapshot.session.providerMeta ?? {},
5683
- ...threadId ? { threadId } : {},
5684
- ...threadPath ? { threadPath } : {}
5685
- };
5686
- }
5687
- function buildCodexAppServerSessionSnapshot(raw, options, targetThreadId) {
5688
- const lines = raw.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
5689
- let resolvedThreadId = targetThreadId?.trim() || null;
5690
- if (!resolvedThreadId) {
5691
- for (const line of lines) {
5692
- try {
5693
- const message = JSON.parse(line);
5694
- const resultThread = message.result?.thread;
5695
- const paramsThread = message.params?.thread;
5696
- const params = message.params;
5697
- const nextThreadId = typeof resultThread?.id === "string" ? resultThread.id : typeof paramsThread?.id === "string" ? paramsThread.id : typeof params?.threadId === "string" ? params.threadId : null;
5698
- if (nextThreadId) {
5699
- resolvedThreadId = nextThreadId;
5700
- }
5701
- } catch {}
5702
- }
5703
- }
5704
- const snapshot = {
5705
- session: {
5706
- id: options.sessionId,
5707
- name: options.agentName,
5708
- adapterType: "codex_app_server",
5709
- status: resolvedThreadId ? "idle" : "connecting",
5710
- cwd: options.cwd,
5711
- providerMeta: resolvedThreadId ? { threadId: resolvedThreadId } : undefined
5712
- },
5713
- turns: []
5714
- };
5715
- const turnsById = new Map;
5716
- const blocksById = new Map;
5717
- const ensureTurn = (turnId) => {
5718
- const existing = turnsById.get(turnId);
5719
- if (existing) {
5720
- return existing;
5721
- }
5722
- const turn = {
5723
- id: turnId,
5724
- status: "streaming",
5725
- blocks: [],
5726
- startedAt: Date.now(),
5727
- nextBlockIndex: 0
5728
- };
5729
- turnsById.set(turnId, turn);
5730
- snapshot.turns.push(turn);
5731
- snapshot.currentTurnId = turnId;
5732
- snapshot.session.status = "active";
5733
- return turn;
5734
- };
5735
- const completeBlock = (blockState) => {
5736
- if (!blockState) {
5737
- return;
5738
- }
5739
- blockState.status = "completed";
5740
- blockState.block.status = "completed";
5741
- };
5742
- for (const line of lines) {
5743
- let message;
5744
- try {
5745
- message = JSON.parse(line);
5746
- } catch {
5747
- continue;
5748
- }
5749
- const params = message.params;
5750
- const result = message.result;
5751
- const paramsThread = params?.thread;
5752
- const resultThread = result?.thread;
5753
- const lineThreadId = typeof params?.threadId === "string" ? params.threadId : typeof paramsThread?.id === "string" ? paramsThread.id : typeof resultThread?.id === "string" ? resultThread.id : null;
5754
- if (resolvedThreadId) {
5755
- if (lineThreadId && lineThreadId !== resolvedThreadId) {
5756
- continue;
5757
- }
5758
- if (!lineThreadId && !isCodexThreadGlobalMessage(message)) {
5759
- continue;
5760
- }
5761
- }
5762
- const resultModel = typeof result?.model === "string" ? result.model : null;
5763
- if (resultThread && resultModel) {
5764
- snapshot.session.model = resultModel;
5765
- }
5766
- if (typeof resultThread?.path === "string") {
5767
- snapshot.session.providerMeta = {
5768
- ...snapshot.session.providerMeta ?? {},
5769
- threadId: resolvedThreadId ?? resultThread.id,
5770
- threadPath: resultThread.path
5771
- };
5772
- }
5773
- if (typeof resultThread?.cwd === "string") {
5774
- snapshot.session.cwd = resultThread.cwd;
5775
- }
5776
- if (message.method === "thread/started" || message.method === "thread/name/updated") {
5777
- if (typeof paramsThread?.path === "string") {
5778
- snapshot.session.providerMeta = {
5779
- ...snapshot.session.providerMeta ?? {},
5780
- threadId: resolvedThreadId ?? paramsThread.id,
5781
- threadPath: paramsThread.path
5782
- };
5783
- }
5784
- if (typeof paramsThread?.cwd === "string") {
5785
- snapshot.session.cwd = paramsThread.cwd;
5786
- }
5787
- if (typeof paramsThread?.name === "string" && paramsThread.name.trim()) {
5788
- snapshot.session.name = paramsThread.name;
5789
- }
5790
- continue;
5791
- }
5792
- if (message.method === "thread/status/changed") {
5793
- const status = params?.status?.type;
5794
- snapshot.session.status = codexThreadStatusToSessionStatus(typeof status === "string" ? status : undefined);
5795
- continue;
5796
- }
5797
- if (message.method === "turn/started") {
5798
- const turn = params?.turn;
5799
- if (typeof turn?.id === "string") {
5800
- ensureTurn(turn.id);
5801
- }
5802
- continue;
5803
- }
5804
- if (message.method === "item/started") {
5805
- const item = params?.item;
5806
- const turnId = typeof params?.turnId === "string" ? params.turnId : null;
5807
- const itemType = typeof item?.type === "string" ? item.type : "";
5808
- const itemId = typeof item?.id === "string" ? item.id : null;
5809
- if (!turnId || !item || !itemId || !itemType) {
5810
- continue;
5811
- }
5812
- const turn = ensureTurn(turnId);
5813
- if (itemType === "userMessage") {
5814
- const block2 = {
5815
- id: itemId,
5816
- turnId,
5817
- index: turn.nextBlockIndex++,
5818
- type: "text",
5819
- text: extractCodexUserMessageText(item),
5820
- status: "streaming"
5821
- };
5822
- const blockState2 = { block: block2, status: "streaming" };
5823
- turn.blocks.push(blockState2);
5824
- blocksById.set(itemId, blockState2);
5825
- continue;
5826
- }
5827
- if (itemType === "agentMessage") {
5828
- const block2 = {
5829
- id: itemId,
5830
- turnId,
5831
- index: turn.nextBlockIndex++,
5832
- type: "text",
5833
- text: typeof item.text === "string" ? item.text : "",
5834
- status: "streaming"
5835
- };
5836
- const blockState2 = { block: block2, status: "streaming" };
5837
- turn.blocks.push(blockState2);
5838
- blocksById.set(itemId, blockState2);
5839
- continue;
5840
- }
5841
- if (itemType === "reasoning") {
5842
- const text = extractCodexReasoningText(item);
5843
- if (!text) {
5844
- continue;
5845
- }
5846
- const block2 = {
5847
- id: itemId,
5848
- turnId,
5849
- index: turn.nextBlockIndex++,
5850
- type: "reasoning",
5851
- text,
5852
- status: "streaming"
5853
- };
5854
- const blockState2 = { block: block2, status: "streaming" };
5855
- turn.blocks.push(blockState2);
5856
- blocksById.set(itemId, blockState2);
5857
- continue;
5858
- }
5859
- const block = buildCodexActionBlock(item, turnId, turn.nextBlockIndex++);
5860
- const blockState = { block, status: "streaming" };
5861
- turn.blocks.push(blockState);
5862
- blocksById.set(block.id, blockState);
5863
- continue;
5864
- }
5865
- if (message.method === "item/agentMessage/delta") {
5866
- const itemId = typeof params?.itemId === "string" ? params.itemId : null;
5867
- const delta = typeof params?.delta === "string" ? params.delta : "";
5868
- const blockState = itemId ? blocksById.get(itemId) : undefined;
5869
- if (blockState?.block.type === "text") {
5870
- blockState.block.text += delta;
5871
- }
5872
- continue;
5873
- }
5874
- if (message.method === "item/completed") {
5875
- const item = params?.item;
5876
- const turnId = typeof params?.turnId === "string" ? params.turnId : null;
5877
- const itemType = typeof item?.type === "string" ? item.type : "";
5878
- const itemId = typeof item?.id === "string" ? item.id : null;
5879
- if (!turnId || !item || !itemId || !itemType) {
5880
- continue;
5881
- }
5882
- if (itemType === "userMessage") {
5883
- const turn2 = ensureTurn(turnId);
5884
- let blockState2 = blocksById.get(itemId);
5885
- if (!blockState2) {
5886
- const block = {
5887
- id: itemId,
5888
- turnId,
5889
- index: turn2.nextBlockIndex++,
5890
- type: "text",
5891
- text: "",
5892
- status: "streaming"
5893
- };
5894
- blockState2 = { block, status: "streaming" };
5895
- turn2.blocks.push(blockState2);
5896
- blocksById.set(itemId, blockState2);
5897
- }
5898
- if (blockState2.block.type === "text") {
5899
- blockState2.block.text = extractCodexUserMessageText(item);
5900
- }
5901
- completeBlock(blockState2);
5902
- continue;
5903
- }
5904
- if (itemType === "agentMessage") {
5905
- const turn2 = ensureTurn(turnId);
5906
- let blockState2 = blocksById.get(itemId);
5907
- if (!blockState2) {
5908
- const block = {
5909
- id: itemId,
5910
- turnId,
5911
- index: turn2.nextBlockIndex++,
5912
- type: "text",
5913
- text: "",
5914
- status: "streaming"
5915
- };
5916
- blockState2 = { block, status: "streaming" };
5917
- turn2.blocks.push(blockState2);
5918
- blocksById.set(itemId, blockState2);
5919
- }
5920
- if (blockState2.block.type === "text" && typeof item.text === "string" && item.text.length > 0) {
5921
- blockState2.block.text = item.text;
5922
- }
5923
- completeBlock(blockState2);
5924
- continue;
5925
- }
5926
- if (itemType === "reasoning") {
5927
- const text = extractCodexReasoningText(item);
5928
- if (!text) {
5929
- continue;
5930
- }
5931
- const turn2 = ensureTurn(turnId);
5932
- let blockState2 = blocksById.get(itemId);
5933
- if (!blockState2) {
5934
- const block = {
5935
- id: itemId,
5936
- turnId,
5937
- index: turn2.nextBlockIndex++,
5938
- type: "reasoning",
5939
- text,
5940
- status: "streaming"
5941
- };
5942
- blockState2 = { block, status: "streaming" };
5943
- turn2.blocks.push(blockState2);
5944
- blocksById.set(itemId, blockState2);
5945
- }
5946
- if (blockState2.block.type === "reasoning" && text) {
5947
- blockState2.block.text = text;
5948
- }
5949
- completeBlock(blockState2);
5950
- continue;
5951
- }
5952
- const turn = ensureTurn(turnId);
5953
- let blockState = blocksById.get(itemId);
5954
- if (!blockState) {
5955
- const block = buildCodexActionBlock(item, turnId, turn.nextBlockIndex++);
5956
- blockState = { block, status: "streaming" };
5957
- turn.blocks.push(blockState);
5958
- blocksById.set(itemId, blockState);
5959
- }
5960
- if (blockState.block.type === "action") {
5961
- blockState.block.action.output = renderCodexActionOutput(item);
5962
- blockState.block.action.status = "completed";
5963
- }
5964
- completeBlock(blockState);
5965
- continue;
5966
- }
5967
- if (message.method === "turn/completed") {
5968
- const turn = params?.turn;
5969
- if (!turn || typeof turn.id !== "string") {
5970
- continue;
5971
- }
5972
- const turnState = ensureTurn(turn.id);
5973
- turnState.status = codexTurnStatusToTurnStatus(typeof turn.status === "string" ? turn.status : undefined);
5974
- turnState.endedAt = Date.now();
5975
- if (snapshot.currentTurnId === turn.id) {
5976
- snapshot.currentTurnId = undefined;
5977
- }
5978
- snapshot.session.status = turnState.status === "error" ? "error" : "idle";
5979
- continue;
5980
- }
5981
- if (message.method === "error") {
5982
- snapshot.session.status = "error";
5983
- }
5984
- }
5985
- if (!resolvedThreadId && snapshot.turns.length === 0) {
5986
- return null;
5987
- }
5988
- return snapshot;
5989
- }
5990
- function buildCodexRolloutSessionSnapshot(raw, options, targetThreadId, rolloutPath) {
5991
- const lines = raw.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
5992
- let resolvedThreadId = targetThreadId?.trim() || null;
5993
- const snapshot = {
5994
- session: {
5995
- id: options.sessionId,
5996
- name: options.agentName,
5997
- adapterType: "codex_app_server",
5998
- status: resolvedThreadId ? "idle" : "connecting",
5999
- cwd: options.cwd
6000
- },
6001
- turns: []
6002
- };
6003
- setCodexProviderMeta(snapshot, resolvedThreadId, rolloutPath ?? null);
6004
- const turnsById = new Map;
6005
- const blocksByCallId = new Map;
6006
- let currentTurnId = null;
6007
- const ensureTurn = (turnId, startedAt) => {
6008
- const existing = turnsById.get(turnId);
6009
- if (existing) {
6010
- if (startedAt && !existing.startedAt) {
6011
- existing.startedAt = startedAt;
6012
- }
6013
- return existing;
6014
- }
6015
- const turn = {
6016
- id: turnId,
6017
- status: "streaming",
6018
- blocks: [],
6019
- startedAt: startedAt ?? Date.now(),
6020
- nextBlockIndex: 0
6021
- };
6022
- turnsById.set(turnId, turn);
6023
- snapshot.turns.push(turn);
6024
- snapshot.currentTurnId = turnId;
6025
- snapshot.session.status = "active";
6026
- return turn;
6027
- };
6028
- for (const line of lines) {
6029
- const message = parseJsonRecord(line);
6030
- if (!message) {
6031
- continue;
6032
- }
6033
- const timestamp = parseCodexTimestamp(message.timestamp) ?? Date.now();
6034
- const entryType = typeof message.type === "string" ? message.type : "";
6035
- const payload = message.payload && typeof message.payload === "object" && !Array.isArray(message.payload) ? message.payload : undefined;
6036
- if (!payload) {
6037
- continue;
6038
- }
6039
- if (entryType === "session_meta") {
6040
- const sessionThreadId = typeof payload.id === "string" ? payload.id : null;
6041
- if (sessionThreadId) {
6042
- if (resolvedThreadId && sessionThreadId !== resolvedThreadId) {
6043
- return null;
6044
- }
6045
- resolvedThreadId = sessionThreadId;
6046
- }
6047
- if (typeof payload.cwd === "string" && payload.cwd.trim()) {
6048
- snapshot.session.cwd = payload.cwd;
6049
- }
6050
- setCodexProviderMeta(snapshot, resolvedThreadId, rolloutPath ?? null);
6051
- snapshot.session.status = resolvedThreadId ? "idle" : snapshot.session.status;
6052
- continue;
6053
- }
6054
- if (entryType === "turn_context") {
6055
- if (typeof payload.cwd === "string" && payload.cwd.trim()) {
6056
- snapshot.session.cwd = payload.cwd;
6057
- }
6058
- if (typeof payload.model === "string" && payload.model.trim()) {
6059
- snapshot.session.model = payload.model;
6060
- }
6061
- continue;
6062
- }
6063
- if (entryType === "event_msg") {
6064
- const payloadType2 = typeof payload.type === "string" ? payload.type : "";
6065
- if (payloadType2 === "task_started") {
6066
- const turnId = typeof payload.turn_id === "string" ? payload.turn_id : null;
6067
- if (!turnId) {
6068
- continue;
6069
- }
6070
- currentTurnId = turnId;
6071
- ensureTurn(turnId, parseCodexTimestamp(payload.started_at) ?? timestamp);
6072
- snapshot.currentTurnId = turnId;
6073
- snapshot.session.status = "active";
6074
- continue;
6075
- }
6076
- if (payloadType2 === "task_complete" || payloadType2 === "turn_aborted") {
6077
- const turnId = typeof payload.turn_id === "string" ? payload.turn_id : currentTurnId;
6078
- if (!turnId) {
6079
- continue;
6080
- }
6081
- const turn2 = ensureTurn(turnId);
6082
- turn2.status = payloadType2 === "task_complete" ? "completed" : payload.reason === "interrupted" ? "interrupted" : "error";
6083
- turn2.endedAt = parseCodexTimestamp(payload.completed_at) ?? timestamp;
6084
- finalizeCodexTurnBlocks(turn2, turn2.status);
6085
- if (snapshot.currentTurnId === turnId) {
6086
- snapshot.currentTurnId = undefined;
6087
- }
6088
- currentTurnId = currentTurnId === turnId ? null : currentTurnId;
6089
- snapshot.session.status = turn2.status === "error" ? "error" : "idle";
6090
- }
6091
- continue;
6092
- }
6093
- if (entryType !== "response_item" || !currentTurnId) {
6094
- continue;
6095
- }
6096
- const turn = ensureTurn(currentTurnId);
6097
- const payloadType = typeof payload.type === "string" ? payload.type : "";
6098
- if (payloadType === "message" && payload.role === "user") {
6099
- const text = extractCodexMessageText(payload);
6100
- if (!text) {
6101
- continue;
6102
- }
6103
- const block = {
6104
- id: `${turn.id}:text:${turn.nextBlockIndex}`,
6105
- turnId: turn.id,
6106
- index: turn.nextBlockIndex++,
6107
- type: "text",
6108
- text,
6109
- status: "completed"
6110
- };
6111
- turn.blocks.push({ block, status: "completed" });
6112
- continue;
6113
- }
6114
- if (payloadType === "message" && payload.role === "assistant") {
6115
- const text = extractCodexMessageText(payload);
6116
- if (!text) {
6117
- continue;
6118
- }
6119
- const block = {
6120
- id: `${turn.id}:text:${turn.nextBlockIndex}`,
6121
- turnId: turn.id,
6122
- index: turn.nextBlockIndex++,
6123
- type: "text",
6124
- text,
6125
- status: "completed"
6126
- };
6127
- turn.blocks.push({ block, status: "completed" });
6128
- continue;
6129
- }
6130
- if (payloadType === "reasoning") {
6131
- const text = extractCodexReasoningText(payload);
6132
- if (!text) {
6133
- continue;
6134
- }
6135
- const block = {
6136
- id: `${turn.id}:reasoning:${turn.nextBlockIndex}`,
6137
- turnId: turn.id,
6138
- index: turn.nextBlockIndex++,
6139
- type: "reasoning",
6140
- text,
6141
- status: "completed"
6142
- };
6143
- turn.blocks.push({ block, status: "completed" });
6144
- continue;
6145
- }
6146
- if (payloadType === "function_call" || payloadType === "custom_tool_call" || payloadType === "web_search_call") {
6147
- const block = buildCodexRolloutActionBlock(payload, turn.id, turn.nextBlockIndex++);
6148
- const blockState = { block, status: "streaming" };
6149
- turn.blocks.push(blockState);
6150
- blocksByCallId.set(block.id, blockState);
6151
- continue;
6152
- }
6153
- if (payloadType === "function_call_output" || payloadType === "custom_tool_call_output") {
6154
- const callId = typeof payload.call_id === "string" ? payload.call_id : null;
6155
- if (!callId) {
6156
- continue;
6157
- }
6158
- let blockState = blocksByCallId.get(callId);
6159
- if (!blockState) {
6160
- const block = buildCodexRolloutActionBlock({
6161
- type: "tool_call",
6162
- call_id: callId,
6163
- name: "unknown"
6164
- }, turn.id, turn.nextBlockIndex++);
6165
- blockState = { block, status: "streaming" };
6166
- turn.blocks.push(blockState);
6167
- blocksByCallId.set(callId, blockState);
6168
- }
6169
- if (blockState.block.type === "action") {
6170
- blockState.block.action.output = stringifyCodexItem(payload.output);
6171
- blockState.block.action.status = "completed";
6172
- }
6173
- blockState.status = "completed";
6174
- blockState.block.status = "completed";
6175
- }
6176
- }
6177
- if (!resolvedThreadId && snapshot.turns.length === 0) {
6178
- return null;
6179
- }
6180
- setCodexProviderMeta(snapshot, resolvedThreadId, rolloutPath ?? null);
6181
- snapshot.session.status = snapshot.currentTurnId ? "active" : snapshot.session.status;
6182
- return snapshot;
6183
- }
6184
4968
  function isMissingCodexRolloutError(error) {
6185
4969
  const message = errorMessage2(error).toLowerCase();
6186
4970
  return message.includes("no rollout found for thread id");
@@ -6827,48 +5611,10 @@ async function ensureCodexAppServerAgentOnline(options) {
6827
5611
  session.update(options);
6828
5612
  return session.ensureOnline();
6829
5613
  }
6830
- async function invokeCodexAppServerAgent(options) {
6831
- const session = getOrCreateSession2(options);
6832
- session.update(options);
6833
- return session.invoke(options.prompt, options.timeoutMs);
6834
- }
6835
- async function sendCodexAppServerAgent(options) {
6836
- const session = getOrCreateSession2(options);
6837
- session.update(options);
6838
- if (session.hasActiveTurn()) {
6839
- return session.steerAndWait(options.prompt, options.timeoutMs);
6840
- }
6841
- return session.invoke(options.prompt, options.timeoutMs);
6842
- }
6843
5614
  function isCodexAppServerAgentAlive(options) {
6844
5615
  const session = sessions2.get(sessionKey2(options));
6845
5616
  return Boolean(session?.isAlive());
6846
5617
  }
6847
- async function getCodexAppServerAgentSnapshot(options) {
6848
- const stdoutLogPath = join6(options.logsDirectory, "stdout.log");
6849
- const threadIdPath = join6(options.runtimeDirectory, "codex-thread-id.txt");
6850
- const statePath = join6(options.runtimeDirectory, "state.json");
6851
- const [rawLog, persistedThreadId, persistedState] = await Promise.all([
6852
- readOptionalFile2(stdoutLogPath),
6853
- readOptionalFile2(threadIdPath),
6854
- readOptionalJsonRecord(statePath)
6855
- ]);
6856
- const resolvedThreadId = options.threadId ?? persistedThreadId ?? metadataString(persistedState ?? undefined, "threadId") ?? undefined;
6857
- const persistedThreadPath = metadataString(persistedState ?? undefined, "threadPath");
6858
- if (persistedThreadPath) {
6859
- const rawRollout = await readOptionalFile2(persistedThreadPath);
6860
- if (rawRollout) {
6861
- const rolloutSnapshot = buildCodexRolloutSessionSnapshot(rawRollout, options, resolvedThreadId, persistedThreadPath);
6862
- if (rolloutSnapshot) {
6863
- return rolloutSnapshot;
6864
- }
6865
- }
6866
- }
6867
- if (!rawLog) {
6868
- return null;
6869
- }
6870
- return buildCodexAppServerSessionSnapshot(rawLog, options, resolvedThreadId);
6871
- }
6872
5618
  async function shutdownCodexAppServerAgent(options, shutdownOptions = {}) {
6873
5619
  const key = sessionKey2(options);
6874
5620
  const session = sessions2.get(key);
@@ -6888,49 +5634,6 @@ var init_codex_app_server = __esm(() => {
6888
5634
  });
6889
5635
 
6890
5636
  // ../runtime/src/collaboration-contract.ts
6891
- function metadataValue(metadata, key) {
6892
- return metadata?.[key];
6893
- }
6894
- function recordFromInvocation(invocation, key) {
6895
- const contextRecord = metadataValue(invocation.context, key);
6896
- if (typeof contextRecord !== "undefined") {
6897
- return contextRecord;
6898
- }
6899
- const nestedContext = metadataValue(invocation.context, "collaboration");
6900
- if (nestedContext && typeof nestedContext === "object" && !Array.isArray(nestedContext)) {
6901
- const nestedValue = metadataValue(nestedContext, key);
6902
- if (typeof nestedValue !== "undefined") {
6903
- return nestedValue;
6904
- }
6905
- }
6906
- const metadataRecord2 = metadataValue(invocation.metadata, key);
6907
- if (typeof metadataRecord2 !== "undefined") {
6908
- return metadataRecord2;
6909
- }
6910
- const nestedMetadata = metadataValue(invocation.metadata, "collaboration");
6911
- if (nestedMetadata && typeof nestedMetadata === "object" && !Array.isArray(nestedMetadata)) {
6912
- return metadataValue(nestedMetadata, key);
6913
- }
6914
- return;
6915
- }
6916
- function stringFromInvocation(invocation, key) {
6917
- const value = recordFromInvocation(invocation, key);
6918
- return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
6919
- }
6920
- function waitingOnLabel(value) {
6921
- if (typeof value === "string" && value.trim().length > 0) {
6922
- return value.trim();
6923
- }
6924
- if (!value || typeof value !== "object" || Array.isArray(value)) {
6925
- return;
6926
- }
6927
- const waitingOn = value;
6928
- const kind = typeof waitingOn.kind === "string" ? waitingOn.kind : undefined;
6929
- const label = typeof waitingOn.label === "string" ? waitingOn.label.trim() : "";
6930
- const targetId = typeof waitingOn.targetId === "string" ? waitingOn.targetId.trim() : "";
6931
- const parts = [label || kind, targetId || undefined].filter(Boolean);
6932
- return parts.length > 0 ? parts.join(" \xB7 ") : undefined;
6933
- }
6934
5637
  function buildCollaborationContractPrompt(agentId) {
6935
5638
  return [
6936
5639
  "Collaboration contract:",
@@ -6947,38 +5650,6 @@ function buildCollaborationContractPrompt(agentId) {
6947
5650
  ].join(`
6948
5651
  `);
6949
5652
  }
6950
- function buildInvocationCollaborationContextPrompt(invocation) {
6951
- const recordId = stringFromInvocation(invocation, "recordId") ?? stringFromInvocation(invocation, "collaborationRecordId");
6952
- const kind = stringFromInvocation(invocation, "kind") ?? stringFromInvocation(invocation, "collaborationKind");
6953
- const state = stringFromInvocation(invocation, "state") ?? stringFromInvocation(invocation, "collaborationState");
6954
- const ownerId = stringFromInvocation(invocation, "ownerId");
6955
- const nextMoveOwnerId = stringFromInvocation(invocation, "nextMoveOwnerId");
6956
- const wakeReason = stringFromInvocation(invocation, "wakeReason");
6957
- const targetAgentId = stringFromInvocation(invocation, "targetAgentId");
6958
- const waitingOn = waitingOnLabel(recordFromInvocation(invocation, "waitingOn") ?? recordFromInvocation(invocation, "waiting_on"));
6959
- const acceptanceState = stringFromInvocation(invocation, "acceptanceState");
6960
- const requestedById = stringFromInvocation(invocation, "requestedById");
6961
- const askedById = stringFromInvocation(invocation, "askedById");
6962
- const askedOfId = stringFromInvocation(invocation, "askedOfId");
6963
- const lines = [
6964
- recordId ? ` - Record: ${kind ? `${kind} ` : ""}${recordId}` : undefined,
6965
- state ? ` - State: ${state}` : undefined,
6966
- ownerId ? ` - Owner: ${ownerId}` : undefined,
6967
- nextMoveOwnerId ? ` - Next move owner: ${nextMoveOwnerId}` : undefined,
6968
- wakeReason ? ` - Wake reason: ${wakeReason}` : undefined,
6969
- targetAgentId ? ` - Wake target: ${targetAgentId}` : undefined,
6970
- waitingOn ? ` - Waiting on: ${waitingOn}` : undefined,
6971
- acceptanceState ? ` - Acceptance: ${acceptanceState}` : undefined,
6972
- requestedById ? ` - Requested by: ${requestedById}` : undefined,
6973
- askedById ? ` - Asked by: ${askedById}` : undefined,
6974
- askedOfId ? ` - Asked of: ${askedOfId}` : undefined
6975
- ].filter((value) => Boolean(value));
6976
- if (lines.length === 0) {
6977
- return;
6978
- }
6979
- return ["Collaboration context:", ...lines].join(`
6980
- `);
6981
- }
6982
5653
 
6983
5654
  // ../runtime/src/broker-service.ts
6984
5655
  import { spawnSync } from "child_process";
@@ -7507,43 +6178,6 @@ var init_local_agent_template = __esm(() => {
7507
6178
  });
7508
6179
 
7509
6180
  // ../runtime/src/local-agents.ts
7510
- var exports_local_agents = {};
7511
- __export(exports_local_agents, {
7512
- updateLocalAgentConfig: () => updateLocalAgentConfig,
7513
- stripLocalAgentReplyMetadata: () => stripLocalAgentReplyMetadata,
7514
- stopLocalAgent: () => stopLocalAgent,
7515
- stopAllLocalAgents: () => stopAllLocalAgents,
7516
- startLocalAgent: () => startLocalAgent,
7517
- shutdownLocalSessionEndpoint: () => shutdownLocalSessionEndpoint,
7518
- shouldDisableGeneratedCodexEndpoint: () => shouldDisableGeneratedCodexEndpoint,
7519
- sendTmuxPrompt: () => sendTmuxPrompt,
7520
- restartLocalAgent: () => restartLocalAgent,
7521
- restartAllLocalAgents: () => restartAllLocalAgents,
7522
- resolveLocalAgentIdentity: () => resolveLocalAgentIdentity,
7523
- resolveLocalAgentByName: () => resolveLocalAgentByName,
7524
- renderLocalAgentSystemPromptTemplate: () => renderLocalAgentSystemPromptTemplate,
7525
- loadRegisteredLocalAgentBindings: () => loadRegisteredLocalAgentBindings,
7526
- listLocalAgents: () => listLocalAgents,
7527
- isLocalAgentSessionAlive: () => isLocalAgentSessionAlive,
7528
- isLocalAgentEndpointAlive: () => isLocalAgentEndpointAlive,
7529
- invokeLocalAgentEndpoint: () => invokeLocalAgentEndpoint,
7530
- interruptLocalAgent: () => interruptLocalAgent,
7531
- inferLocalAgentBinding: () => inferLocalAgentBinding,
7532
- getLocalAgentSessionSnapshot: () => getLocalAgentSessionSnapshot,
7533
- getLocalAgentEndpointSessionSnapshot: () => getLocalAgentEndpointSessionSnapshot,
7534
- getLocalAgentConfig: () => getLocalAgentConfig,
7535
- ensureLocalSessionEndpointOnline: () => ensureLocalSessionEndpointOnline,
7536
- ensureLocalAgentBindingOnline: () => ensureLocalAgentBindingOnline,
7537
- buildTmuxLaunchShellCommand: () => buildTmuxLaunchShellCommand,
7538
- buildLocalAgentSystemPromptTemplate: () => buildLocalAgentSystemPromptTemplate,
7539
- buildLocalAgentSystemPrompt: () => buildLocalAgentSystemPrompt,
7540
- buildLocalAgentNudge: () => buildLocalAgentNudge,
7541
- buildLocalAgentDirectInvocationPrompt: () => buildLocalAgentDirectInvocationPrompt,
7542
- buildAttachedSessionInvocationPrompt: () => buildAttachedSessionInvocationPrompt,
7543
- answerLocalAgentSessionQuestion: () => answerLocalAgentSessionQuestion,
7544
- SUPPORTED_LOCAL_AGENT_HARNESSES: () => SUPPORTED_LOCAL_AGENT_HARNESSES
7545
- });
7546
- import { randomUUID as randomUUID2 } from "crypto";
7547
6181
  import { execFileSync as execFileSync3, execSync } from "child_process";
7548
6182
  import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
7549
6183
  import { mkdir as mkdir5, rm as rm4, stat as stat3, writeFile as writeFile5 } from "fs/promises";
@@ -7574,21 +6208,9 @@ function resolveBrokerUrl() {
7574
6208
  function nowSeconds2() {
7575
6209
  return Math.floor(Date.now() / 1000);
7576
6210
  }
7577
- function normalizeBrokerTimestamp(value) {
7578
- return value > 10000000000 ? Math.floor(value / 1000) : value;
7579
- }
7580
6211
  function brokerRelayCommand() {
7581
6212
  return `node ${JSON.stringify(join8(OPENSCOUT_REPO_ROOT, "packages", "cli", "bin", "scout.mjs"))}`;
7582
6213
  }
7583
- function sleep2(ms) {
7584
- return new Promise((resolve7) => setTimeout(resolve7, ms));
7585
- }
7586
- function createLocalAgentFlightId() {
7587
- return `f-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;
7588
- }
7589
- function escapeRegExp(value) {
7590
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
7591
- }
7592
6214
  function titleCaseLocalAgentName(value) {
7593
6215
  return value.split(/[-_.\s]+/).filter(Boolean).map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1)).join(" ");
7594
6216
  }
@@ -7833,13 +6455,6 @@ function expandHomePath3(value) {
7833
6455
  function normalizeProjectPath(value) {
7834
6456
  return resolve6(expandHomePath3(value.trim() || "."));
7835
6457
  }
7836
- function compactHomePath(value) {
7837
- const home = process.env.HOME;
7838
- if (!home) {
7839
- return value;
7840
- }
7841
- return value.startsWith(home) ? value.replace(home, "~") : value;
7842
- }
7843
6458
  function normalizeTmuxSessionName2(value, agentId) {
7844
6459
  const fallback = `relay-${agentId}`;
7845
6460
  const trimmed = value?.trim() ?? "";
@@ -8085,134 +6700,6 @@ function relayAgentOverrideFromLocalAgentRecord(agentId, record, existing) {
8085
6700
  }
8086
6701
  };
8087
6702
  }
8088
- function buildLocalAgentConfigState(agentId, record) {
8089
- return {
8090
- agentId,
8091
- editable: true,
8092
- systemPrompt: record.systemPrompt || buildLocalAgentSystemPromptTemplate(),
8093
- runtime: {
8094
- cwd: compactHomePath(record.cwd),
8095
- harness: normalizeLocalAgentHarness(record.harness),
8096
- transport: normalizeLocalAgentTransport(record.transport, normalizeLocalAgentHarness(record.harness)),
8097
- sessionId: record.tmuxSession,
8098
- wakePolicy: "on_demand"
8099
- },
8100
- launchArgs: normalizeLocalAgentLaunchArgs(record.launchArgs),
8101
- capabilities: normalizeLocalAgentCapabilities(record.capabilities),
8102
- applyMode: "restart",
8103
- templateHint: LOCAL_AGENT_SYSTEM_PROMPT_TEMPLATE_HINT
8104
- };
8105
- }
8106
- async function assertDirectoryExists(directory) {
8107
- const stats = await stat3(directory);
8108
- if (!stats.isDirectory()) {
8109
- throw new Error(`${directory} is not a directory.`);
8110
- }
8111
- }
8112
- async function resolveConfiguredLocalAgentRecord(agentId) {
8113
- const overrides = await readRelayAgentOverrides();
8114
- const override = overrides[agentId];
8115
- if (override) {
8116
- return localAgentRecordFromRelayAgentOverride(agentId, override);
8117
- }
8118
- const registry = await readLocalAgentRegistry();
8119
- const record = registry[agentId];
8120
- return record ? normalizeLocalAgentRecord(agentId, record) : null;
8121
- }
8122
- async function getLocalAgentConfig(agentId) {
8123
- const record = await resolveConfiguredLocalAgentRecord(agentId);
8124
- if (!record) {
8125
- return null;
8126
- }
8127
- return buildLocalAgentConfigState(agentId, record);
8128
- }
8129
- async function getLocalAgentSessionSnapshot(agentId) {
8130
- const record = await resolveConfiguredLocalAgentRecord(agentId);
8131
- if (!record) {
8132
- return null;
8133
- }
8134
- if (record.transport === "codex_app_server") {
8135
- return getCodexAppServerAgentSnapshot(buildCodexAgentSessionOptions(agentId, record));
8136
- }
8137
- if (record.transport === "claude_stream_json") {
8138
- return getClaudeStreamJsonAgentSnapshot(buildClaudeAgentSessionOptions(agentId, record));
8139
- }
8140
- return null;
8141
- }
8142
- async function getLocalAgentEndpointSessionSnapshot(endpoint) {
8143
- if (endpoint.transport === "codex_app_server") {
8144
- return getCodexAppServerAgentSnapshot(buildCodexEndpointSessionOptions(endpoint));
8145
- }
8146
- if (endpoint.transport === "claude_stream_json") {
8147
- return getClaudeStreamJsonAgentSnapshot(buildClaudeEndpointSessionOptions(endpoint));
8148
- }
8149
- return null;
8150
- }
8151
- async function ensureLocalSessionEndpointOnline(endpoint) {
8152
- if (endpoint.transport === "codex_app_server") {
8153
- await ensureCodexAppServerAgentOnline(buildCodexEndpointSessionOptions(endpoint));
8154
- return;
8155
- }
8156
- if (endpoint.transport === "claude_stream_json") {
8157
- await ensureClaudeStreamJsonAgentOnline(buildClaudeEndpointSessionOptions(endpoint));
8158
- }
8159
- }
8160
- async function shutdownLocalSessionEndpoint(endpoint) {
8161
- if (endpoint.transport === "codex_app_server") {
8162
- await shutdownCodexAppServerAgent(buildCodexEndpointSessionOptions(endpoint));
8163
- return;
8164
- }
8165
- if (endpoint.transport === "claude_stream_json") {
8166
- await shutdownClaudeStreamJsonAgent(buildClaudeEndpointSessionOptions(endpoint));
8167
- }
8168
- }
8169
- async function answerLocalAgentSessionQuestion(agentId, input) {
8170
- const record = await resolveConfiguredLocalAgentRecord(agentId);
8171
- if (!record) {
8172
- throw new Error(`Agent ${agentId} is not configured.`);
8173
- }
8174
- if (record.transport !== "claude_stream_json") {
8175
- throw new Error(`Agent ${agentId} does not support direct question answers for transport ${record.transport}.`);
8176
- }
8177
- await answerClaudeStreamJsonQuestion(buildClaudeAgentSessionOptions(agentId, record), input);
8178
- }
8179
- async function updateLocalAgentConfig(agentId, input) {
8180
- const [registry, overrides] = await Promise.all([
8181
- readLocalAgentRegistry(),
8182
- readRelayAgentOverrides()
8183
- ]);
8184
- const record = registry[agentId] ?? (overrides[agentId] ? localAgentRecordFromRelayAgentOverride(agentId, overrides[agentId]) : undefined);
8185
- if (!record) {
8186
- return null;
8187
- }
8188
- const cwd = normalizeProjectPath(input.runtime.cwd || record.cwd);
8189
- await assertDirectoryExists(cwd);
8190
- const nextHarness = normalizeLocalAgentHarness(input.runtime.harness);
8191
- const nextTransport = normalizeLocalAgentTransport(input.runtime.transport ?? record.transport, nextHarness);
8192
- const nextRecord = normalizeLocalAgentRecord(agentId, {
8193
- ...record,
8194
- cwd,
8195
- tmuxSession: input.runtime.sessionId,
8196
- harness: nextHarness,
8197
- defaultHarness: nextHarness,
8198
- harnessProfiles: {
8199
- ...record.harnessProfiles ?? {},
8200
- [normalizeManagedHarness2(input.runtime.harness, "claude")]: {
8201
- cwd,
8202
- transport: nextTransport,
8203
- sessionId: normalizeTmuxSessionName2(input.runtime.sessionId, `${agentId}-${normalizeManagedHarness2(input.runtime.harness, "claude")}`),
8204
- launchArgs: input.launchArgs
8205
- }
8206
- },
8207
- transport: nextTransport,
8208
- systemPrompt: input.systemPrompt.trim() || undefined,
8209
- launchArgs: input.launchArgs,
8210
- capabilities: input.capabilities
8211
- });
8212
- registry[agentId] = nextRecord;
8213
- await writeLocalAgentRegistry(registry);
8214
- return buildLocalAgentConfigState(agentId, nextRecord);
8215
- }
8216
6703
  function buildCodexAgentSessionOptions(agentName, record, systemPrompt) {
8217
6704
  return {
8218
6705
  agentName,
@@ -8235,72 +6722,6 @@ function buildClaudeAgentSessionOptions(agentName, record, systemPrompt) {
8235
6722
  launchArgs: normalizeLocalAgentLaunchArgs(record.launchArgs)
8236
6723
  };
8237
6724
  }
8238
- function endpointMetadataString(endpoint, key) {
8239
- const value = endpoint.metadata?.[key];
8240
- return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
8241
- }
8242
- function endpointInvocationPrompt(endpoint, agentName, invocation) {
8243
- const source = endpointMetadataString(endpoint, "source");
8244
- const externalSource = endpointMetadataString(endpoint, "externalSource");
8245
- const attachedTransport = endpointMetadataString(endpoint, "attachedTransport");
8246
- const sessionBacked = endpoint.metadata?.sessionBacked === true;
8247
- if (invocation.action === "consult" && (sessionBacked || source === "local-session" || externalSource === "local-session" || attachedTransport === "codex_app_server" || attachedTransport === "claude_stream_json")) {
8248
- return invocation.task;
8249
- }
8250
- if (sessionBacked) {
8251
- return buildAttachedSessionInvocationPrompt(invocation);
8252
- }
8253
- return buildLocalAgentDirectInvocationPrompt(agentName, invocation);
8254
- }
8255
- function isSessionBackedEndpoint(endpoint) {
8256
- const source = endpointMetadataString(endpoint, "source");
8257
- const externalSource = endpointMetadataString(endpoint, "externalSource");
8258
- const attachedTransport = endpointMetadataString(endpoint, "attachedTransport");
8259
- return endpoint.metadata?.sessionBacked === true || source === "local-session" || externalSource === "local-session" || attachedTransport === "codex_app_server" || attachedTransport === "claude_stream_json";
8260
- }
8261
- function endpointAgentName(endpoint) {
8262
- return endpointMetadataString(endpoint, "agentName") ?? endpointMetadataString(endpoint, "definitionId") ?? endpoint.agentId;
8263
- }
8264
- function endpointRuntimeInstanceId(endpoint) {
8265
- return endpointMetadataString(endpoint, "runtimeInstanceId") ?? endpointMetadataString(endpoint, "runtimeSessionId") ?? endpoint.sessionId ?? `relay-${endpointAgentName(endpoint)}`;
8266
- }
8267
- function endpointCwd(endpoint) {
8268
- return endpoint.cwd ?? endpoint.projectRoot ?? process.cwd();
8269
- }
8270
- function attachedLocalSessionSystemPrompt(endpoint) {
8271
- const explicit = endpointMetadataString(endpoint, "systemPrompt");
8272
- if (explicit) {
8273
- return explicit;
8274
- }
8275
- return "Resume the existing session without changing its identity or prior context.";
8276
- }
8277
- function buildCodexEndpointSessionOptions(endpoint) {
8278
- const agentName = endpointAgentName(endpoint);
8279
- const threadId = endpointMetadataString(endpoint, "threadId") ?? endpointMetadataString(endpoint, "externalSessionId") ?? endpoint.sessionId ?? undefined;
8280
- return {
8281
- agentName,
8282
- sessionId: endpointRuntimeInstanceId(endpoint),
8283
- cwd: endpointCwd(endpoint),
8284
- systemPrompt: attachedLocalSessionSystemPrompt(endpoint),
8285
- runtimeDirectory: relayAgentRuntimeDirectory(agentName),
8286
- logsDirectory: relayAgentLogsDirectory(agentName),
8287
- launchArgs: [],
8288
- threadId,
8289
- requireExistingThread: Boolean(threadId)
8290
- };
8291
- }
8292
- function buildClaudeEndpointSessionOptions(endpoint) {
8293
- const agentName = endpointAgentName(endpoint);
8294
- return {
8295
- agentName,
8296
- sessionId: endpointRuntimeInstanceId(endpoint),
8297
- cwd: endpointCwd(endpoint),
8298
- systemPrompt: attachedLocalSessionSystemPrompt(endpoint),
8299
- runtimeDirectory: relayAgentRuntimeDirectory(agentName),
8300
- logsDirectory: relayAgentLogsDirectory(agentName),
8301
- launchArgs: []
8302
- };
8303
- }
8304
6725
  function isLocalAgentRecordOnline(agentName, record) {
8305
6726
  const normalizedRecord = normalizeLocalAgentRecord(agentName, record);
8306
6727
  if (normalizedRecord.transport === "codex_app_server") {
@@ -8319,117 +6740,12 @@ function isLocalAgentSessionAlive(sessionName) {
8319
6740
  return false;
8320
6741
  }
8321
6742
  }
8322
- function isLocalAgentEndpointAlive(endpoint) {
8323
- if (endpoint.transport === "pairing_bridge") {
8324
- return endpoint.state !== "offline";
8325
- }
8326
- if (endpoint.transport === "codex_app_server") {
8327
- return isCodexAppServerAgentAlive(buildCodexEndpointSessionOptions(endpoint));
8328
- }
8329
- if (endpoint.transport === "claude_stream_json") {
8330
- return isClaudeStreamJsonAgentAlive(buildClaudeEndpointSessionOptions(endpoint));
8331
- }
8332
- const sessionId = endpoint.sessionId ?? (typeof endpoint.metadata?.tmuxSession === "string" ? String(endpoint.metadata.tmuxSession) : null);
8333
- return sessionId ? isLocalAgentSessionAlive(sessionId) : false;
8334
- }
8335
- async function readBrokerMessagesSince(sinceSeconds) {
8336
- const response = await fetch(new URL("/v1/snapshot", resolveBrokerUrl()));
8337
- if (!response.ok) {
8338
- throw new Error(`Broker snapshot failed: ${response.status} ${response.statusText}`);
8339
- }
8340
- const snapshot = await response.json();
8341
- return Object.values(snapshot.messages).filter((message) => normalizeBrokerTimestamp(message.createdAt) >= sinceSeconds).sort((lhs, rhs) => normalizeBrokerTimestamp(lhs.createdAt) - normalizeBrokerTimestamp(rhs.createdAt));
8342
- }
8343
6743
  function buildLocalAgentSystemPrompt(agentName, projectName, projectPath, options = {}) {
8344
6744
  return renderLocalAgentSystemPromptTemplate(buildLocalAgentSystemPromptTemplate(), buildLocalAgentTemplateContext(agentName, projectName, projectPath), options);
8345
6745
  }
8346
6746
  function buildLocalAgentInitialMessage(projectName, agentName) {
8347
6747
  return `You are now online as the ${agentName} relay agent for ${projectName}. Announce yourself on the relay with: ${brokerRelayCommand()} send --as ${agentName} "relay agent online \u2014 ready to assist with ${projectName}"`;
8348
6748
  }
8349
- function buildLocalAgentDirectInvocationPrompt(agentName, invocation) {
8350
- const contextLines = Object.entries(invocation.context ?? {}).map(([key, value]) => `- ${key}: ${String(value)}`);
8351
- const collaborationContract = buildCollaborationContractPrompt(agentName);
8352
- const collaborationContext = buildInvocationCollaborationContextPrompt(invocation);
8353
- const actionRules = invocation.action === "execute" ? "You may inspect and modify the workspace when needed. End with the concise broker-visible reply for the requester." : "Do not modify files unless the request explicitly requires it. End with the concise broker-visible reply for the requester.";
8354
- return [
8355
- `OpenScout invocation for ${agentName}.`,
8356
- `Requester: ${invocation.requesterId}.`,
8357
- `Action: ${invocation.action}.`,
8358
- invocation.conversationId ? `Conversation: ${invocation.conversationId}.` : undefined,
8359
- invocation.messageId ? `Message: ${invocation.messageId}.` : undefined,
8360
- "",
8361
- actionRules,
8362
- collaborationContract,
8363
- "Return only the reply that should be delivered back through the broker.",
8364
- "",
8365
- collaborationContext,
8366
- contextLines.length > 0 ? `Context:
8367
- ${contextLines.join(`
8368
- `)}` : undefined,
8369
- "Task:",
8370
- invocation.task
8371
- ].filter((value) => Boolean(value && value.length > 0)).join(`
8372
- `);
8373
- }
8374
- function buildAttachedSessionInvocationPrompt(invocation) {
8375
- const contextLines = Object.entries(invocation.context ?? {}).map(([key, value]) => `- ${key}: ${String(value)}`);
8376
- return [
8377
- `Scout message from ${invocation.requesterId}.`,
8378
- invocation.conversationId ? `Conversation: ${invocation.conversationId}.` : undefined,
8379
- invocation.messageId ? `Reply-To Message: ${invocation.messageId}.` : undefined,
8380
- invocation.action !== "consult" ? `Requested action: ${invocation.action}.` : undefined,
8381
- "Treat this as a direct message to the current session and reply normally as yourself in this session.",
8382
- contextLines.length > 0 ? `Context:
8383
- ${contextLines.join(`
8384
- `)}` : undefined,
8385
- "",
8386
- invocation.task
8387
- ].filter((value) => Boolean(value && value.length > 0)).join(`
8388
- `);
8389
- }
8390
- function buildLocalAgentNudge(agentName, invocation, flightId) {
8391
- const relayCommand = brokerRelayCommand();
8392
- const parts = [
8393
- `New broker ask from ${invocation.requesterId}.`,
8394
- `Task: ${invocation.task}`,
8395
- "Follow the OpenScout collaboration contract: answer directly if you can, otherwise make the next owner explicit and avoid broad wakeups."
8396
- ];
8397
- if (invocation.context && Object.keys(invocation.context).length > 0) {
8398
- parts.push(`Context: ${JSON.stringify(invocation.context)}`);
8399
- }
8400
- parts.push(`Read recent context if needed: ${relayCommand} read -n 20 --as ${agentName}.`);
8401
- parts.push(`Reply with: ${relayCommand} send --as ${agentName} "[ask:${flightId}] @${invocation.requesterId} <your response>"`);
8402
- return parts.join(" ");
8403
- }
8404
- function stripLocalAgentReplyMetadata(body, flightId, asker) {
8405
- return body.replace(new RegExp(`\\[ask:${escapeRegExp(flightId)}\\]`, "g"), "").replace(new RegExp(`@${escapeRegExp(asker)}`, "g"), "").trim();
8406
- }
8407
- async function sendLocalAgentPrompt(agentName, record, prompt) {
8408
- if (normalizeLocalAgentHarness(record.harness) === "codex") {
8409
- const promptPipe = join8(relayAgentRuntimeDirectory(agentName), "prompt.pipe");
8410
- await writeFile5(promptPipe, prompt.trim() + "\x00");
8411
- return;
8412
- }
8413
- sendTmuxPrompt(record.tmuxSession, prompt);
8414
- }
8415
- function sendTmuxPrompt(sessionName, prompt) {
8416
- const bufferName = `openscout-prompt-${randomUUID2()}`;
8417
- try {
8418
- execFileSync3("tmux", ["load-buffer", "-b", bufferName, "-"], {
8419
- stdio: "pipe",
8420
- input: prompt
8421
- });
8422
- execFileSync3("tmux", ["paste-buffer", "-d", "-b", bufferName, "-t", sessionName], {
8423
- stdio: "pipe"
8424
- });
8425
- execFileSync3("tmux", ["send-keys", "-t", sessionName, "Enter"], { stdio: "pipe" });
8426
- } catch (error) {
8427
- try {
8428
- execFileSync3("tmux", ["delete-buffer", "-b", bufferName], { stdio: "pipe" });
8429
- } catch {}
8430
- throw error;
8431
- }
8432
- }
8433
6749
  function shellQuoteArguments(args) {
8434
6750
  return args.map((arg) => JSON.stringify(arg)).join(" ");
8435
6751
  }
@@ -9125,110 +7441,6 @@ async function ensureLocalAgentBindingOnline(agentId, nodeId, options = {}) {
9125
7441
  const onlineRecord = await ensureLocalAgentOnline(agentId, recordForHarness(localAgentRecordFromRelayAgentOverride(agentId, override), options.harness));
9126
7442
  return buildLocalAgentBinding(agentId, onlineRecord, isLocalAgentRecordOnline(agentId, onlineRecord), nodeId, "relay-agent-registry");
9127
7443
  }
9128
- async function invokeLocalAgentEndpoint(endpoint, invocation) {
9129
- const agentRuntimeId = endpoint.agentId;
9130
- const definitionId = String(endpoint.metadata?.definitionId ?? endpoint.metadata?.agentName ?? endpoint.agentId);
9131
- const prompt = endpointInvocationPrompt(endpoint, definitionId, invocation);
9132
- const registry = await readLocalAgentRegistry();
9133
- const existing = registry[agentRuntimeId];
9134
- if (!existing && endpoint.transport === "codex_app_server") {
9135
- await ensureLocalSessionEndpointOnline(endpoint);
9136
- const invoke = isSessionBackedEndpoint(endpoint) ? sendCodexAppServerAgent : invokeCodexAppServerAgent;
9137
- const result = await invoke({
9138
- ...buildCodexEndpointSessionOptions(endpoint),
9139
- prompt,
9140
- timeoutMs: invocation.timeoutMs
9141
- });
9142
- return {
9143
- output: result.output
9144
- };
9145
- }
9146
- if (!existing && endpoint.transport === "claude_stream_json") {
9147
- await ensureLocalSessionEndpointOnline(endpoint);
9148
- const result = await invokeClaudeStreamJsonAgent({
9149
- ...buildClaudeEndpointSessionOptions(endpoint),
9150
- prompt,
9151
- timeoutMs: invocation.timeoutMs
9152
- });
9153
- return {
9154
- output: result.output
9155
- };
9156
- }
9157
- const projectRoot = endpoint.projectRoot ?? endpoint.cwd;
9158
- const requestedHarness = invocation.execution?.harness;
9159
- const record = existing ?? (projectRoot ? {
9160
- definitionId,
9161
- project: basename3(projectRoot),
9162
- projectRoot,
9163
- tmuxSession: String(endpoint.metadata?.tmuxSession ?? `relay-${agentRuntimeId}`),
9164
- cwd: projectRoot,
9165
- startedAt: nowSeconds2(),
9166
- harness: normalizeLocalAgentHarness(typeof endpoint.harness === "string" ? endpoint.harness : undefined),
9167
- defaultHarness: normalizeLocalAgentHarness(typeof endpoint.harness === "string" ? endpoint.harness : undefined),
9168
- harnessProfiles: {
9169
- [normalizeManagedHarness2(typeof endpoint.harness === "string" ? endpoint.harness : undefined, "claude")]: {
9170
- cwd: projectRoot,
9171
- sessionId: String(endpoint.sessionId ?? endpoint.metadata?.runtimeInstanceId ?? endpoint.metadata?.runtimeSessionId ?? `relay-${agentRuntimeId}`),
9172
- transport: normalizeLocalAgentTransport(typeof endpoint.transport === "string" ? endpoint.transport : undefined, normalizeLocalAgentHarness(typeof endpoint.harness === "string" ? endpoint.harness : undefined)),
9173
- launchArgs: []
9174
- }
9175
- },
9176
- transport: normalizeLocalAgentTransport(typeof endpoint.transport === "string" ? endpoint.transport : undefined, normalizeLocalAgentHarness(typeof endpoint.harness === "string" ? endpoint.harness : undefined)),
9177
- capabilities: [...DEFAULT_LOCAL_AGENT_CAPABILITIES],
9178
- launchArgs: []
9179
- } : null);
9180
- if (!record) {
9181
- throw new Error(`Agent ${agentRuntimeId} is not registered and has no project root.`);
9182
- }
9183
- const selectedRecord = recordForHarness(record, requestedHarness);
9184
- const onlineRecord = await ensureLocalAgentOnline(agentRuntimeId, selectedRecord);
9185
- if (onlineRecord.transport === "codex_app_server") {
9186
- const result = await invokeCodexAppServerAgent({
9187
- ...buildCodexAgentSessionOptions(agentRuntimeId, onlineRecord, renderLocalAgentSystemPromptTemplate(onlineRecord.systemPrompt || buildLocalAgentSystemPromptTemplate(), buildLocalAgentTemplateContext(definitionId, onlineRecord.project, onlineRecord.cwd), { transport: "codex_app_server" })),
9188
- prompt,
9189
- timeoutMs: invocation.timeoutMs
9190
- });
9191
- return {
9192
- output: result.output
9193
- };
9194
- }
9195
- if (onlineRecord.transport === "claude_stream_json") {
9196
- const result = await invokeClaudeStreamJsonAgent({
9197
- ...buildClaudeAgentSessionOptions(agentRuntimeId, onlineRecord, renderLocalAgentSystemPromptTemplate(onlineRecord.systemPrompt || buildLocalAgentSystemPromptTemplate(), buildLocalAgentTemplateContext(definitionId, onlineRecord.project, onlineRecord.cwd), { transport: "claude_stream_json" })),
9198
- prompt,
9199
- timeoutMs: invocation.timeoutMs
9200
- });
9201
- return {
9202
- output: result.output
9203
- };
9204
- }
9205
- const flightId = createLocalAgentFlightId();
9206
- const askedAt = nowSeconds2();
9207
- const timeoutSeconds = invocation.timeoutMs ? Math.max(30, Math.floor(invocation.timeoutMs / 1000)) : 300;
9208
- await sendLocalAgentPrompt(agentRuntimeId, onlineRecord, buildLocalAgentNudge(definitionId, invocation, flightId));
9209
- const deadline = Date.now() + timeoutSeconds * 1000;
9210
- while (Date.now() <= deadline) {
9211
- const messages2 = await readBrokerMessagesSince(askedAt - 1);
9212
- for (let index = messages2.length - 1;index >= 0; index -= 1) {
9213
- const message = messages2[index];
9214
- if (message.actorId !== agentRuntimeId)
9215
- continue;
9216
- if (!message.body.includes(`[ask:${flightId}]`))
9217
- continue;
9218
- return {
9219
- output: stripLocalAgentReplyMetadata(message.body, flightId, invocation.requesterId)
9220
- };
9221
- }
9222
- await sleep2(500);
9223
- }
9224
- throw new Error(`Timed out after ${timeoutSeconds}s waiting for ${agentRuntimeId}.`);
9225
- }
9226
- function shouldDisableGeneratedCodexEndpoint(endpoint) {
9227
- if (endpoint.transport !== "codex_exec") {
9228
- return false;
9229
- }
9230
- return endpoint.metadata?.source === "scout-app";
9231
- }
9232
7444
  var MODULE_DIRECTORY, OPENSCOUT_REPO_ROOT, DEFAULT_LOCAL_AGENT_CAPABILITIES, DEFAULT_LOCAL_AGENT_HARNESS = "claude", SUPPORTED_LOCAL_AGENT_HARNESSES;
9233
7445
  var init_local_agents = __esm(async () => {
9234
7446
  init_src();
@@ -9326,19 +7538,41 @@ function resolveScoutAgentName(agentName) {
9326
7538
  }
9327
7539
  return resolveOperatorName();
9328
7540
  }
9329
- async function resolveScoutSenderId(agentName, currentDirectory) {
7541
+ function resolveConfiguredSenderIdForProjectRoot(overrides, projectRoot) {
7542
+ for (const [agentId, override] of Object.entries(overrides)) {
7543
+ if (BUILT_IN_AGENT_DEFINITION_IDS.has(agentId)) {
7544
+ continue;
7545
+ }
7546
+ if (!override.projectRoot || override.projectRoot !== projectRoot) {
7547
+ continue;
7548
+ }
7549
+ return agentId;
7550
+ }
7551
+ return null;
7552
+ }
7553
+ async function inferSenderIdForProjectRoot(projectRoot) {
7554
+ const overrides = await readRelayAgentOverrides();
7555
+ const configuredSenderId = resolveConfiguredSenderIdForProjectRoot(overrides, projectRoot);
7556
+ if (configuredSenderId) {
7557
+ return configuredSenderId;
7558
+ }
7559
+ const projectConfig = await readProjectConfig(projectRoot);
7560
+ const configuredDefinitionId = normalizeAgentSelectorSegment(projectConfig?.agent?.id?.trim() ?? "");
7561
+ const definitionId = configuredDefinitionId || normalizeAgentSelectorSegment(basename4(projectRoot)) || "agent";
7562
+ return buildRelayAgentInstance(definitionId, projectRoot).id;
7563
+ }
7564
+ async function resolveScoutSenderId(agentName, currentDirectory, env = process.env) {
9330
7565
  if (agentName?.trim()) {
9331
7566
  return agentName.trim();
9332
7567
  }
9333
- if (process.env.OPENSCOUT_AGENT?.trim()) {
9334
- return process.env.OPENSCOUT_AGENT.trim();
7568
+ if (env.OPENSCOUT_AGENT?.trim()) {
7569
+ return env.OPENSCOUT_AGENT.trim();
7570
+ }
7571
+ const projectRoot = await findNearestProjectRoot(currentDirectory);
7572
+ if (!projectRoot) {
7573
+ return resolveOperatorName();
9335
7574
  }
9336
- const { findNearestProjectRoot: findNearestProjectRoot2 } = await Promise.resolve().then(() => (init_setup(), exports_setup));
9337
- const { resolveLocalAgentByName: resolveLocalAgentByName2 } = await init_local_agents().then(() => exports_local_agents);
9338
- const projectRoot = await findNearestProjectRoot2(currentDirectory) ?? currentDirectory;
9339
- const projectName = basename4(projectRoot);
9340
- const agent = await resolveLocalAgentByName2(projectName);
9341
- return agent?.agentId ?? projectName;
7575
+ return inferSenderIdForProjectRoot(projectRoot);
9342
7576
  }
9343
7577
  function parseScoutHarness(value) {
9344
7578
  const trimmed = value?.trim();
@@ -9912,14 +8146,17 @@ async function sendScoutMessage(input) {
9912
8146
  const senderId = await resolveConversationActorId(broker.baseUrl, broker.snapshot, broker.node.id, input.senderId, currentDirectory);
9913
8147
  const availableTargets = (await Promise.all(mentionResolution.resolved.map(async (target) => await ensureTargetRelayAgentRegistered(broker.baseUrl, broker.snapshot, broker.node.id, target.agentId, currentDirectory) ? target : null))).filter((target) => Boolean(target));
9914
8148
  const validTargets = [...new Set(availableTargets.map((target) => target.agentId).filter((target) => target !== senderId && Boolean(broker.snapshot.agents[target])))].sort();
8149
+ const unresolvedTargets = mentionResolution.resolved.filter((target) => !validTargets.includes(target.agentId)).map((target) => target.label).concat(mentionResolution.unresolved).concat(mentionResolution.ambiguous.map((entry) => entry.label));
8150
+ if (unresolvedTargets.length > 0) {
8151
+ return { usedBroker: true, invokedTargets: [], unresolvedTargets };
8152
+ }
9915
8153
  let conversation;
9916
8154
  if (validTargets.length === 1 && !input.channel) {
9917
8155
  const dm = await ensureBrokerDirectConversationBetween(broker.baseUrl, broker.snapshot, broker.node.id, senderId, validTargets[0]);
9918
8156
  conversation = dm.conversation;
9919
8157
  } else {
9920
- conversation = await ensureBrokerConversation(broker.baseUrl, broker.snapshot, broker.node.id, input.channel, senderId, availableTargets.map((target) => target.agentId));
8158
+ conversation = await ensureBrokerConversation(broker.baseUrl, broker.snapshot, broker.node.id, input.channel, senderId, validTargets);
9921
8159
  }
9922
- const unresolvedTargets = mentionResolution.resolved.filter((target) => !validTargets.includes(target.agentId)).map((target) => target.label).concat(mentionResolution.unresolved).concat(mentionResolution.ambiguous.map((entry) => entry.label));
9923
8160
  const messageId = `m-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;
9924
8161
  const speechText = input.shouldSpeak ? stripScoutAgentSelectorLabels(input.body) : "";
9925
8162
  const returnAddress = buildScoutReturnAddress(broker.snapshot, senderId, {
@@ -9946,27 +8183,6 @@ async function sendScoutMessage(input) {
9946
8183
  returnAddress
9947
8184
  }
9948
8185
  });
9949
- for (const targetAgentId of validTargets) {
9950
- await brokerPostJson(broker.baseUrl, scoutBrokerPaths.v1.invocations, {
9951
- id: `inv-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`,
9952
- requesterId: senderId,
9953
- requesterNodeId: broker.node.id,
9954
- targetAgentId,
9955
- action: "consult",
9956
- task: input.body,
9957
- conversationId: conversation.id,
9958
- messageId,
9959
- execution: input.executionHarness ? { harness: input.executionHarness } : undefined,
9960
- ensureAwake: true,
9961
- stream: false,
9962
- createdAt: Date.now(),
9963
- metadata: {
9964
- source: "scout-cli",
9965
- relayChannel: input.channel ?? "shared",
9966
- returnAddress
9967
- }
9968
- });
9969
- }
9970
8186
  return { usedBroker: true, invokedTargets: validTargets, unresolvedTargets };
9971
8187
  }
9972
8188
  async function openScoutPeerSession(input) {
@@ -10251,7 +8467,7 @@ async function watchScoutMessages(options) {
10251
8467
  return;
10252
8468
  }
10253
8469
  const message = event.payload?.message;
10254
- if (!message || message.conversationId !== conversationId || message.actorId === options.agentId)
8470
+ if (!message || message.conversationId !== conversationId)
10255
8471
  return;
10256
8472
  options.onMessage(message);
10257
8473
  };
@@ -10548,13 +8764,15 @@ async function runAskCommand(context, args) {
10548
8764
  await runAskWithOptions(context, options);
10549
8765
  }
10550
8766
  async function runAskWithOptions(context, options) {
8767
+ const currentDirectory = options.currentDirectory ?? defaultScoutContextDirectory(context);
8768
+ const senderId = await resolveScoutSenderId(options.agentName, currentDirectory, context.env);
10551
8769
  const result = await askScoutQuestion({
10552
- senderId: resolveScoutAgentName(options.agentName),
8770
+ senderId,
10553
8771
  targetLabel: options.targetLabel,
10554
8772
  body: options.message,
10555
8773
  channel: options.channel,
10556
8774
  executionHarness: parseScoutHarness(options.harness),
10557
- currentDirectory: options.currentDirectory
8775
+ currentDirectory
10558
8776
  });
10559
8777
  if (!result.usedBroker) {
10560
8778
  throw new Error("broker is not reachable");
@@ -10703,6 +8921,57 @@ function renderScoutActivityList(items) {
10703
8921
  }
10704
8922
  var init_broker = () => {};
10705
8923
 
8924
+ // ../../apps/desktop/src/cli/commands/send.ts
8925
+ var exports_send = {};
8926
+ __export(exports_send, {
8927
+ runSendCommand: () => runSendCommand,
8928
+ formatScoutSendRoutingError: () => formatScoutSendRoutingError
8929
+ });
8930
+ function renderTargetLabel(label) {
8931
+ const trimmed = label.trim();
8932
+ if (!trimmed) {
8933
+ return "";
8934
+ }
8935
+ return trimmed.startsWith("@") ? trimmed : `@${trimmed}`;
8936
+ }
8937
+ function formatScoutSendRoutingError(unresolvedTargets) {
8938
+ const rendered = unresolvedTargets.map(renderTargetLabel).filter((label) => label.length > 0);
8939
+ if (rendered.length === 1) {
8940
+ return `target ${rendered[0]} is not uniquely routable; nothing was sent.`;
8941
+ }
8942
+ return `targets ${rendered.join(", ")} are not uniquely routable; nothing was sent.`;
8943
+ }
8944
+ async function runSendCommand(context, args) {
8945
+ const options = parseSendCommandOptions(args, defaultScoutContextDirectory(context));
8946
+ const currentDirectory = options.currentDirectory ?? defaultScoutContextDirectory(context);
8947
+ const senderId = await resolveScoutSenderId(options.agentName, currentDirectory, context.env);
8948
+ const result = await sendScoutMessage({
8949
+ senderId,
8950
+ body: options.message,
8951
+ channel: options.channel,
8952
+ shouldSpeak: options.shouldSpeak,
8953
+ executionHarness: parseScoutHarness(options.harness),
8954
+ currentDirectory: options.currentDirectory
8955
+ });
8956
+ if (!result.usedBroker) {
8957
+ throw new Error("broker is not reachable");
8958
+ }
8959
+ if (result.unresolvedTargets.length > 0) {
8960
+ throw new Error(formatScoutSendRoutingError(result.unresolvedTargets));
8961
+ }
8962
+ context.output.writeValue({
8963
+ message: options.message,
8964
+ invokedTargets: result.invokedTargets,
8965
+ unresolvedTargets: result.unresolvedTargets
8966
+ }, renderScoutMessagePostResult);
8967
+ }
8968
+ var init_send = __esm(async () => {
8969
+ init_context();
8970
+ init_options();
8971
+ init_broker();
8972
+ await init_service();
8973
+ });
8974
+
10706
8975
  // ../../apps/desktop/src/cli/commands/broadcast.ts
10707
8976
  var exports_broadcast = {};
10708
8977
  __export(exports_broadcast, {
@@ -10710,15 +8979,20 @@ __export(exports_broadcast, {
10710
8979
  });
10711
8980
  async function runBroadcastCommand(context, args) {
10712
8981
  const options = parseSendCommandOptions(args, defaultScoutContextDirectory(context));
8982
+ const currentDirectory = options.currentDirectory ?? defaultScoutContextDirectory(context);
8983
+ const senderId = await resolveScoutSenderId(options.agentName, currentDirectory, context.env);
10713
8984
  const result = await sendScoutMessage({
10714
- senderId: resolveScoutAgentName(options.agentName),
8985
+ senderId,
10715
8986
  body: `@all ${options.message}`,
10716
8987
  executionHarness: parseScoutHarness(options.harness),
10717
- currentDirectory: options.currentDirectory
8988
+ currentDirectory
10718
8989
  });
10719
8990
  if (!result.usedBroker) {
10720
8991
  throw new Error("broker is not reachable");
10721
8992
  }
8993
+ if (result.unresolvedTargets.length > 0) {
8994
+ throw new Error(formatScoutSendRoutingError(result.unresolvedTargets));
8995
+ }
10722
8996
  context.output.writeValue({
10723
8997
  message: options.message,
10724
8998
  invokedTargets: result.invokedTargets,
@@ -10729,7 +9003,10 @@ var init_broadcast = __esm(async () => {
10729
9003
  init_context();
10730
9004
  init_options();
10731
9005
  init_broker();
10732
- await init_service();
9006
+ await __promiseAll([
9007
+ init_service(),
9008
+ init_send()
9009
+ ]);
10733
9010
  });
10734
9011
 
10735
9012
  // ../runtime/src/relay-agent-cards.ts
@@ -11822,7 +10099,7 @@ function resolveScoutBinPath(appRoot) {
11822
10099
  }
11823
10100
  return candidates[candidates.length - 1];
11824
10101
  }
11825
- function loadScoutEnvReport(context, currentDirectory) {
10102
+ async function loadScoutEnvReport(context, currentDirectory) {
11826
10103
  const appRoot = resolveScoutAppRoot({
11827
10104
  currentDirectory,
11828
10105
  env: context.env
@@ -11840,6 +10117,8 @@ function loadScoutEnvReport(context, currentDirectory) {
11840
10117
  const binPath = resolveScoutBinPath(appRoot);
11841
10118
  const scoutPath = resolveCommandOnPath("scout", context.env);
11842
10119
  const fallbackCommand = `bun ${binPath}`;
10120
+ const resolvedId = await resolveScoutSenderId(null, currentDirectory, context.env);
10121
+ const projectRoot = await findNearestProjectRoot(currentDirectory);
11843
10122
  return {
11844
10123
  executable: {
11845
10124
  command: scoutPath ? "scout" : fallbackCommand,
@@ -11847,8 +10126,9 @@ function loadScoutEnvReport(context, currentDirectory) {
11847
10126
  scoutPath
11848
10127
  },
11849
10128
  agent: {
11850
- resolvedId: context.env.OPENSCOUT_AGENT?.trim() || "operator",
11851
- envAgent: context.env.OPENSCOUT_AGENT?.trim() || null
10129
+ resolvedId,
10130
+ envAgent: context.env.OPENSCOUT_AGENT?.trim() || null,
10131
+ projectRoot
11852
10132
  },
11853
10133
  context: {
11854
10134
  cwd: context.cwd,
@@ -11875,10 +10155,11 @@ function renderScoutEnvReport(report) {
11875
10155
  }
11876
10156
  async function runEnvCommand(context, args) {
11877
10157
  const options = parseContextRootCommandOptions("env", args, defaultScoutContextDirectory(context));
11878
- const report = loadScoutEnvReport(context, options.currentDirectory);
10158
+ const report = await loadScoutEnvReport(context, options.currentDirectory);
11879
10159
  context.output.writeValue(report, renderScoutEnvReport);
11880
10160
  }
11881
10161
  var init_env = __esm(async () => {
10162
+ init_setup();
11882
10163
  init_context();
11883
10164
  init_options();
11884
10165
  init_paths2();
@@ -11907,6 +10188,273 @@ var init_latest = __esm(async () => {
11907
10188
  await init_service();
11908
10189
  });
11909
10190
 
10191
+ // ../../apps/desktop/src/cli/commands/menu.ts
10192
+ var exports_menu = {};
10193
+ __export(exports_menu, {
10194
+ runMenuCommand: () => runMenuCommand,
10195
+ renderMenuCommandHelp: () => renderMenuCommandHelp,
10196
+ parseMenuCommand: () => parseMenuCommand
10197
+ });
10198
+ import { spawnSync as spawnSync2 } from "child_process";
10199
+ import { existsSync as existsSync10 } from "fs";
10200
+ import { homedir as homedir7 } from "os";
10201
+ import { dirname as dirname10, join as join15, resolve as resolve8 } from "path";
10202
+ import { fileURLToPath as fileURLToPath7 } from "url";
10203
+ function renderMenuCommandHelp() {
10204
+ return [
10205
+ "scout menu \u2014 macOS menu bar app",
10206
+ "",
10207
+ "Usage:",
10208
+ " scout menu",
10209
+ " scout menu launch",
10210
+ " scout menu status",
10211
+ " scout menu restart",
10212
+ " scout menu quit",
10213
+ " scout menu build",
10214
+ " scout menu dmg",
10215
+ "",
10216
+ "Aliases:",
10217
+ " launch = open = start",
10218
+ " quit = stop",
10219
+ "",
10220
+ "Behavior:",
10221
+ " On macOS, `scout menu` launches the installed OpenScout menu app when available.",
10222
+ " When run inside an OpenScout repo checkout, it prefers `apps/macos/bin/openscout-menu.ts`",
10223
+ " so launch/build/restart reuse the repo helper and auto-build the app bundle if needed.",
10224
+ "",
10225
+ "Examples:",
10226
+ " scout menu",
10227
+ " scout menu status",
10228
+ " scout menu restart",
10229
+ " scout menu build --version 0.2.16"
10230
+ ].join(`
10231
+ `);
10232
+ }
10233
+ function parseMenuCommand(args) {
10234
+ const [first, ...rest] = args;
10235
+ if (!first) {
10236
+ return { action: "launch", passthroughArgs: [] };
10237
+ }
10238
+ if (first.startsWith("-")) {
10239
+ return { action: "launch", passthroughArgs: args };
10240
+ }
10241
+ switch (first) {
10242
+ case "launch":
10243
+ case "open":
10244
+ case "start":
10245
+ return { action: "launch", passthroughArgs: rest };
10246
+ case "restart":
10247
+ return { action: "restart", passthroughArgs: rest };
10248
+ case "quit":
10249
+ case "stop":
10250
+ return { action: "quit", passthroughArgs: rest };
10251
+ case "status":
10252
+ return { action: "status", passthroughArgs: rest };
10253
+ case "build":
10254
+ return { action: "build", passthroughArgs: rest };
10255
+ case "dmg":
10256
+ return { action: "dmg", passthroughArgs: rest };
10257
+ default:
10258
+ throw new ScoutCliError(`unknown subcommand: ${first} (try: scout menu)`);
10259
+ }
10260
+ }
10261
+ function runProcess(command, args, options) {
10262
+ const result = spawnSync2(command, args, {
10263
+ cwd: options.cwd,
10264
+ env: options.env,
10265
+ encoding: "utf8"
10266
+ });
10267
+ if (result.error) {
10268
+ throw new ScoutCliError(`failed to run ${command}: ${result.error.message}`);
10269
+ }
10270
+ const stdout = result.stdout.trim();
10271
+ const stderr = result.stderr.trim();
10272
+ const ok = (result.status ?? 1) === 0;
10273
+ if (!ok && !options.allowFailure) {
10274
+ const detail = stderr || stdout || `${command} ${args.join(" ")} failed`;
10275
+ throw new ScoutCliError(detail);
10276
+ }
10277
+ return {
10278
+ ok,
10279
+ stdout,
10280
+ stderr,
10281
+ status: result.status
10282
+ };
10283
+ }
10284
+ function findRepoMenuHelper(startDirectory) {
10285
+ let current = resolve8(startDirectory);
10286
+ while (true) {
10287
+ const candidate = join15(current, "apps", "macos", "bin", "openscout-menu.ts");
10288
+ if (existsSync10(candidate)) {
10289
+ return candidate;
10290
+ }
10291
+ const parent = dirname10(current);
10292
+ if (parent === current) {
10293
+ break;
10294
+ }
10295
+ current = parent;
10296
+ }
10297
+ const sourceRelativeCandidate = fileURLToPath7(new URL("../../../../macos/bin/openscout-menu.ts", import.meta.url));
10298
+ return existsSync10(sourceRelativeCandidate) ? sourceRelativeCandidate : null;
10299
+ }
10300
+ function resolveRepoBundlePath(helperPath) {
10301
+ return resolve8(dirname10(helperPath), "..", "dist", MENU_BUNDLE_NAME);
10302
+ }
10303
+ function isMenuRunning(env) {
10304
+ return runProcess("pgrep", ["-x", MENU_PROCESS_NAME], { env, allowFailure: true }).ok;
10305
+ }
10306
+ function stopRunningMenu(env) {
10307
+ return runProcess("pkill", ["-x", MENU_PROCESS_NAME], { env, allowFailure: true }).ok;
10308
+ }
10309
+ function resolveInstalledMenuBundlePath(env) {
10310
+ const spotlight = runProcess("mdfind", [`kMDItemCFBundleIdentifier == '${MENU_BUNDLE_ID}'`], { env, allowFailure: true });
10311
+ const indexedPath = spotlight.stdout.split(`
10312
+ `).map((line) => line.trim()).find(Boolean);
10313
+ if (indexedPath) {
10314
+ return indexedPath;
10315
+ }
10316
+ for (const candidate of COMMON_MENU_BUNDLE_PATHS) {
10317
+ if (existsSync10(candidate)) {
10318
+ return candidate;
10319
+ }
10320
+ }
10321
+ return null;
10322
+ }
10323
+ function openInstalledMenuApp(bundlePath, env) {
10324
+ const bundleAttempts = [
10325
+ { command: "open", args: ["-b", MENU_BUNDLE_ID] }
10326
+ ];
10327
+ if (bundlePath) {
10328
+ bundleAttempts.push({ command: "open", args: [bundlePath] });
10329
+ }
10330
+ let lastFailure = "OpenScout Menu is not installed.";
10331
+ for (const attempt of bundleAttempts) {
10332
+ const result = runProcess(attempt.command, attempt.args, { env, allowFailure: true });
10333
+ if (result.ok) {
10334
+ return;
10335
+ }
10336
+ lastFailure = result.stderr || result.stdout || lastFailure;
10337
+ }
10338
+ throw new ScoutCliError(`${lastFailure} Run this command from the OpenScout repo to auto-build the menu app, or install the app first.`);
10339
+ }
10340
+ function renderMenuResult(result) {
10341
+ if (result.action === "status") {
10342
+ const lines2 = [
10343
+ `Installed: ${result.installed ? "yes" : "no"}`,
10344
+ `Running: ${result.running ? "yes" : "no"}`
10345
+ ];
10346
+ if (result.bundlePath) {
10347
+ lines2.splice(1, 0, `Bundle: ${result.bundlePath}`);
10348
+ }
10349
+ if (result.helperPath) {
10350
+ lines2.push(`Helper: ${result.helperPath}`);
10351
+ }
10352
+ return lines2.join(`
10353
+ `);
10354
+ }
10355
+ const lines = [result.message];
10356
+ if (result.bundlePath) {
10357
+ lines.push(`Bundle: ${result.bundlePath}`);
10358
+ }
10359
+ return lines.join(`
10360
+ `);
10361
+ }
10362
+ function renderActionMessage(action) {
10363
+ switch (action) {
10364
+ case "build":
10365
+ return "Built the OpenScout menu app bundle.";
10366
+ case "dmg":
10367
+ return "Built the OpenScout menu app DMG.";
10368
+ case "restart":
10369
+ return "Restarted the OpenScout menu app.";
10370
+ case "quit":
10371
+ return "Stopped the OpenScout menu app.";
10372
+ case "status":
10373
+ return "Checked the OpenScout menu app status.";
10374
+ case "launch":
10375
+ default:
10376
+ return "Opened the OpenScout menu app.";
10377
+ }
10378
+ }
10379
+ function runWithRepoHelper(context, helperPath, command) {
10380
+ runProcess(process.execPath, [helperPath, command.action, ...command.passthroughArgs], {
10381
+ cwd: defaultScoutContextDirectory(context),
10382
+ env: context.env
10383
+ });
10384
+ const bundlePath = resolveRepoBundlePath(helperPath);
10385
+ const running = command.action === "quit" ? false : isMenuRunning(context.env);
10386
+ const installed = existsSync10(bundlePath) || running;
10387
+ return {
10388
+ action: command.action,
10389
+ mode: "repo-helper",
10390
+ bundleId: MENU_BUNDLE_ID,
10391
+ bundlePath,
10392
+ helperPath,
10393
+ installed,
10394
+ running,
10395
+ message: renderActionMessage(command.action)
10396
+ };
10397
+ }
10398
+ function runWithInstalledApp(context, command) {
10399
+ const bundlePath = resolveInstalledMenuBundlePath(context.env);
10400
+ if (command.action === "build" || command.action === "dmg") {
10401
+ throw new ScoutCliError(`scout menu ${command.action} requires an OpenScout repo checkout. Run from the repo root or use bun run macos:${command.action}.`);
10402
+ }
10403
+ switch (command.action) {
10404
+ case "launch":
10405
+ if (!isMenuRunning(context.env)) {
10406
+ openInstalledMenuApp(bundlePath, context.env);
10407
+ }
10408
+ break;
10409
+ case "restart":
10410
+ stopRunningMenu(context.env);
10411
+ openInstalledMenuApp(bundlePath, context.env);
10412
+ break;
10413
+ case "quit":
10414
+ stopRunningMenu(context.env);
10415
+ break;
10416
+ case "status":
10417
+ break;
10418
+ default:
10419
+ break;
10420
+ }
10421
+ const running = command.action === "quit" ? false : isMenuRunning(context.env);
10422
+ const installed = Boolean(bundlePath) || running;
10423
+ return {
10424
+ action: command.action,
10425
+ mode: "installed-app",
10426
+ bundleId: MENU_BUNDLE_ID,
10427
+ bundlePath,
10428
+ helperPath: null,
10429
+ installed,
10430
+ running,
10431
+ message: renderActionMessage(command.action)
10432
+ };
10433
+ }
10434
+ async function runMenuCommand(context, args) {
10435
+ if (HELP_FLAGS.has(args[0] ?? "")) {
10436
+ context.output.writeText(renderMenuCommandHelp());
10437
+ return;
10438
+ }
10439
+ if (process.platform !== "darwin") {
10440
+ throw new ScoutCliError("scout menu is only supported on macOS.");
10441
+ }
10442
+ const command = parseMenuCommand(args);
10443
+ const helperPath = findRepoMenuHelper(defaultScoutContextDirectory(context));
10444
+ const result = helperPath ? runWithRepoHelper(context, helperPath, command) : runWithInstalledApp(context, command);
10445
+ context.output.writeValue(result, renderMenuResult);
10446
+ }
10447
+ var MENU_BUNDLE_ID = "com.openscout.menu", MENU_BUNDLE_NAME = "OpenScoutMenu.app", MENU_PROCESS_NAME = "OpenScoutMenu", HELP_FLAGS, COMMON_MENU_BUNDLE_PATHS;
10448
+ var init_menu = __esm(() => {
10449
+ init_context();
10450
+ init_errors();
10451
+ HELP_FLAGS = new Set(["help", "--help", "-h"]);
10452
+ COMMON_MENU_BUNDLE_PATHS = [
10453
+ join15("/Applications", MENU_BUNDLE_NAME),
10454
+ join15(homedir7(), "Applications", MENU_BUNDLE_NAME)
10455
+ ];
10456
+ });
10457
+
11910
10458
  // ../runtime/src/tailscale.ts
11911
10459
  import { readFile as readFile8 } from "fs/promises";
11912
10460
  import { execFile } from "child_process";
@@ -12369,11 +10917,11 @@ var init_mesh = __esm(async () => {
12369
10917
  });
12370
10918
 
12371
10919
  // ../../apps/desktop/src/core/pairing/runtime/config.ts
12372
- import { existsSync as existsSync10, mkdirSync as mkdirSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
12373
- import { homedir as homedir7 } from "os";
10920
+ import { existsSync as existsSync11, mkdirSync as mkdirSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
10921
+ import { homedir as homedir8 } from "os";
12374
10922
  import path from "path";
12375
10923
  function pairingPaths() {
12376
- const rootDir = path.join(homedir7(), ".scout/pairing");
10924
+ const rootDir = path.join(homedir8(), ".scout/pairing");
12377
10925
  return {
12378
10926
  rootDir,
12379
10927
  configPath: path.join(rootDir, "config.json"),
@@ -12386,7 +10934,7 @@ function pairingPaths() {
12386
10934
  }
12387
10935
  function loadPairingConfig() {
12388
10936
  const { configPath } = pairingPaths();
12389
- if (!existsSync10(configPath)) {
10937
+ if (!existsSync11(configPath)) {
12390
10938
  return {};
12391
10939
  }
12392
10940
  try {
@@ -14473,11 +13021,11 @@ var init_noise = __esm(() => {
14473
13021
  });
14474
13022
 
14475
13023
  // ../../apps/desktop/src/core/pairing/runtime/security/identity.ts
14476
- import { existsSync as existsSync11, mkdirSync as mkdirSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
14477
- import { join as join15 } from "path";
14478
- import { homedir as homedir8 } from "os";
13024
+ import { existsSync as existsSync12, mkdirSync as mkdirSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
13025
+ import { join as join16 } from "path";
13026
+ import { homedir as homedir9 } from "os";
14479
13027
  function loadOrCreateIdentity() {
14480
- if (existsSync11(IDENTITY_FILE)) {
13028
+ if (existsSync12(IDENTITY_FILE)) {
14481
13029
  return loadIdentity();
14482
13030
  }
14483
13031
  return createAndSaveIdentity();
@@ -14501,7 +13049,7 @@ function createAndSaveIdentity() {
14501
13049
  return keyPair;
14502
13050
  }
14503
13051
  function loadTrustedPeers() {
14504
- if (!existsSync11(TRUSTED_PEERS_FILE))
13052
+ if (!existsSync12(TRUSTED_PEERS_FILE))
14505
13053
  return new Map;
14506
13054
  const data = JSON.parse(readFileSync7(TRUSTED_PEERS_FILE, "utf8"));
14507
13055
  return new Map(data.map((p) => [p.publicKey, p]));
@@ -14537,9 +13085,9 @@ function hexToBytes2(hex) {
14537
13085
  var PAIRING_DIR, IDENTITY_FILE, TRUSTED_PEERS_FILE, QR_VERSION = 1, QR_EXPIRY_MS;
14538
13086
  var init_identity = __esm(() => {
14539
13087
  init_noise();
14540
- PAIRING_DIR = join15(homedir8(), ".scout/pairing");
14541
- IDENTITY_FILE = join15(PAIRING_DIR, "identity.json");
14542
- TRUSTED_PEERS_FILE = join15(PAIRING_DIR, "trusted-peers.json");
13088
+ PAIRING_DIR = join16(homedir9(), ".scout/pairing");
13089
+ IDENTITY_FILE = join16(PAIRING_DIR, "identity.json");
13090
+ TRUSTED_PEERS_FILE = join16(PAIRING_DIR, "trusted-peers.json");
14543
13091
  QR_EXPIRY_MS = 5 * 60 * 1000;
14544
13092
  });
14545
13093
 
@@ -14684,10 +13232,10 @@ var init_security2 = __esm(() => {
14684
13232
  });
14685
13233
 
14686
13234
  // ../../apps/desktop/src/core/pairing/runtime/runtime-state.ts
14687
- import { existsSync as existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync8, renameSync, unlinkSync, writeFileSync as writeFileSync6 } from "fs";
13235
+ import { existsSync as existsSync13, mkdirSync as mkdirSync6, readFileSync as readFileSync8, renameSync, unlinkSync, writeFileSync as writeFileSync6 } from "fs";
14688
13236
  function readPairingRuntimeSnapshot() {
14689
13237
  const { runtimeStatePath } = pairingPaths();
14690
- if (!existsSync12(runtimeStatePath)) {
13238
+ if (!existsSync13(runtimeStatePath)) {
14691
13239
  return null;
14692
13240
  }
14693
13241
  try {
@@ -15216,17 +13764,17 @@ var init_registry = __esm(() => {
15216
13764
  });
15217
13765
 
15218
13766
  // ../agent-sessions/src/adapters/claude-code.ts
15219
- import { existsSync as existsSync13, readdirSync, statSync as statSync2 } from "fs";
15220
- import { homedir as homedir9 } from "os";
15221
- import { join as join16 } from "path";
13767
+ import { existsSync as existsSync14, readdirSync, statSync as statSync2 } from "fs";
13768
+ import { homedir as homedir10 } from "os";
13769
+ import { join as join17 } from "path";
15222
13770
  function resolveClaudeResumeContext(config) {
15223
13771
  const rawResumeId = config.options?.["resume"];
15224
13772
  const resumeId = typeof rawResumeId === "string" ? rawResumeId.trim().replace(/\.jsonl$/u, "") : "";
15225
13773
  if (!resumeId) {
15226
13774
  return null;
15227
13775
  }
15228
- const projectsRoot = join16(homedir9(), ".claude", "projects");
15229
- if (!existsSync13(projectsRoot)) {
13776
+ const projectsRoot = join17(homedir10(), ".claude", "projects");
13777
+ if (!existsSync14(projectsRoot)) {
15230
13778
  return null;
15231
13779
  }
15232
13780
  let projectSlugs;
@@ -15236,8 +13784,8 @@ function resolveClaudeResumeContext(config) {
15236
13784
  return null;
15237
13785
  }
15238
13786
  for (const slug of projectSlugs) {
15239
- const sessionPath = join16(projectsRoot, slug, `${resumeId}.jsonl`);
15240
- if (!existsSync13(sessionPath)) {
13787
+ const sessionPath = join17(projectsRoot, slug, `${resumeId}.jsonl`);
13788
+ if (!existsSync14(sessionPath)) {
15241
13789
  continue;
15242
13790
  }
15243
13791
  const cwd = decodeClaudeProjectsSlug2(slug);
@@ -15676,11 +14224,11 @@ Referenced files: ${prompt.files.join(", ")}` });
15676
14224
  });
15677
14225
  }
15678
14226
  answerQuestion(answer) {
15679
- const resolve8 = this.pendingAnswers.get(answer.blockId);
15680
- if (!resolve8)
14227
+ const resolve9 = this.pendingAnswers.get(answer.blockId);
14228
+ if (!resolve9)
15681
14229
  return;
15682
14230
  this.pendingAnswers.delete(answer.blockId);
15683
- resolve8(answer.answer);
14231
+ resolve9(answer.answer);
15684
14232
  const turn = this.currentTurn;
15685
14233
  if (turn) {
15686
14234
  this.emit("event", {
@@ -15694,8 +14242,8 @@ Referenced files: ${prompt.files.join(", ")}` });
15694
14242
  }
15695
14243
  }
15696
14244
  async awaitAndSendAnswer(blockId, toolCallId) {
15697
- const answer = await new Promise((resolve8) => {
15698
- this.pendingAnswers.set(blockId, resolve8);
14245
+ const answer = await new Promise((resolve9) => {
14246
+ this.pendingAnswers.set(blockId, resolve9);
15699
14247
  });
15700
14248
  if (!this.process?.stdin || typeof this.process.stdin === "number")
15701
14249
  return;
@@ -15780,8 +14328,8 @@ Referenced files: ${prompt.files.join(", ")}` });
15780
14328
  // ../agent-sessions/src/adapters/codex.ts
15781
14329
  import { spawn as spawn4 } from "child_process";
15782
14330
  import { access as access3, appendFile as appendFile3, constants as constants2, mkdir as mkdir8, readFile as readFile9, rm as rm6, writeFile as writeFile7 } from "fs/promises";
15783
- import { delimiter as delimiter2, join as join17 } from "path";
15784
- import { homedir as homedir10 } from "os";
14331
+ import { delimiter as delimiter2, join as join18 } from "path";
14332
+ import { homedir as homedir11 } from "os";
15785
14333
  function parseJsonLine2(line) {
15786
14334
  try {
15787
14335
  return JSON.parse(line);
@@ -15931,7 +14479,7 @@ async function resolveCodexExecutable2() {
15931
14479
  "/usr/local/bin"
15932
14480
  ].filter(Boolean);
15933
14481
  for (const directory of [...pathEntries, ...commonDirectories]) {
15934
- const candidate = join17(directory, "codex");
14482
+ const candidate = join18(directory, "codex");
15935
14483
  if (await isExecutable2(candidate)) {
15936
14484
  return candidate;
15937
14485
  }
@@ -16035,7 +14583,7 @@ var init_codex = __esm(() => {
16035
14583
  this.pendingRequests.clear();
16036
14584
  if (child && child.exitCode === null && !child.killed) {
16037
14585
  child.kill("SIGTERM");
16038
- await new Promise((resolve8) => setTimeout(resolve8, 250));
14586
+ await new Promise((resolve9) => setTimeout(resolve9, 250));
16039
14587
  if (child.exitCode === null && !child.killed) {
16040
14588
  child.kill("SIGKILL");
16041
14589
  }
@@ -16044,7 +14592,7 @@ var init_codex = __esm(() => {
16044
14592
  await this.persistState();
16045
14593
  }
16046
14594
  get codexOptions() {
16047
- const runtimeRoot = join17(homedir10(), ".scout/pairing", "codex", this.session.id);
14595
+ const runtimeRoot = join18(homedir11(), ".scout/pairing", "codex", this.session.id);
16048
14596
  const configuredThreadId = this.config.options?.["threadId"];
16049
14597
  const requireExistingThread = this.config.options?.["requireExistingThread"];
16050
14598
  const rawLaunchArgs = this.config.options?.["launchArgs"];
@@ -16054,8 +14602,8 @@ var init_codex = __esm(() => {
16054
14602
  sessionId: this.session.id,
16055
14603
  cwd: this.config.cwd ?? process.cwd(),
16056
14604
  systemPrompt: this.systemPrompt,
16057
- runtimeDirectory: join17(runtimeRoot, "runtime"),
16058
- logsDirectory: join17(runtimeRoot, "logs"),
14605
+ runtimeDirectory: join18(runtimeRoot, "runtime"),
14606
+ logsDirectory: join18(runtimeRoot, "logs"),
16059
14607
  launchArgs,
16060
14608
  threadId: typeof configuredThreadId === "string" && configuredThreadId.trim().length > 0 ? configuredThreadId.trim() : undefined,
16061
14609
  requireExistingThread: requireExistingThread ?? Boolean(configuredThreadId)
@@ -16066,16 +14614,16 @@ var init_codex = __esm(() => {
16066
14614
  return typeof raw === "string" && raw.trim().length > 0 ? raw : "You are a helpful agent working through Pairing.";
16067
14615
  }
16068
14616
  get threadIdPath() {
16069
- return join17(this.codexOptions.runtimeDirectory, "codex-thread-id.txt");
14617
+ return join18(this.codexOptions.runtimeDirectory, "codex-thread-id.txt");
16070
14618
  }
16071
14619
  get statePath() {
16072
- return join17(this.codexOptions.runtimeDirectory, "state.json");
14620
+ return join18(this.codexOptions.runtimeDirectory, "state.json");
16073
14621
  }
16074
14622
  get stdoutLogPath() {
16075
- return join17(this.codexOptions.logsDirectory, "stdout.log");
14623
+ return join18(this.codexOptions.logsDirectory, "stdout.log");
16076
14624
  }
16077
14625
  get stderrLogPath() {
16078
- return join17(this.codexOptions.logsDirectory, "stderr.log");
14626
+ return join18(this.codexOptions.logsDirectory, "stderr.log");
16079
14627
  }
16080
14628
  enqueue(task) {
16081
14629
  const next = this.serialized.then(task, task);
@@ -16104,7 +14652,7 @@ var init_codex = __esm(() => {
16104
14652
  const options = this.codexOptions;
16105
14653
  await mkdir8(options.runtimeDirectory, { recursive: true });
16106
14654
  await mkdir8(options.logsDirectory, { recursive: true });
16107
- await writeFile7(join17(options.runtimeDirectory, "prompt.txt"), options.systemPrompt);
14655
+ await writeFile7(join18(options.runtimeDirectory, "prompt.txt"), options.systemPrompt);
16108
14656
  const codexExecutable = await resolveCodexExecutable2();
16109
14657
  const child = spawn4(codexExecutable, ["app-server", ...options.launchArgs], {
16110
14658
  cwd: options.cwd,
@@ -16821,9 +15369,9 @@ var init_codex = __esm(() => {
16821
15369
  }
16822
15370
  async request(method, params) {
16823
15371
  const id = String(this.nextRequestId++);
16824
- return new Promise((resolve8, reject) => {
15372
+ return new Promise((resolve9, reject) => {
16825
15373
  this.pendingRequests.set(id, {
16826
- resolve: (value) => resolve8(value),
15374
+ resolve: (value) => resolve9(value),
16827
15375
  reject
16828
15376
  });
16829
15377
  try {
@@ -18178,8 +16726,8 @@ var init_echo = __esm(() => {
18178
16726
  blockId: actionId,
18179
16727
  approval: { version: 1, description: `Run echo tool with: ${text}`, risk: "low" }
18180
16728
  });
18181
- const decision = await new Promise((resolve8) => {
18182
- this.pendingApprovals.set(this.approvalKey(turnId, actionId), { resolve: resolve8 });
16729
+ const decision = await new Promise((resolve9) => {
16730
+ this.pendingApprovals.set(this.approvalKey(turnId, actionId), { resolve: resolve9 });
18183
16731
  });
18184
16732
  if (this.interrupted) {
18185
16733
  this.emitTurnEnd(sessionId, turnId, "stopped");
@@ -18254,7 +16802,7 @@ var init_echo = __esm(() => {
18254
16802
  delay() {
18255
16803
  if (this.stepDelay <= 0)
18256
16804
  return Promise.resolve();
18257
- return new Promise((resolve8) => setTimeout(resolve8, this.stepDelay));
16805
+ return new Promise((resolve9) => setTimeout(resolve9, this.stepDelay));
18258
16806
  }
18259
16807
  };
18260
16808
  });
@@ -18273,8 +16821,8 @@ var init_src2 = __esm(() => {
18273
16821
 
18274
16822
  // ../../apps/desktop/src/core/pairing/runtime/bridge/log.ts
18275
16823
  import { appendFileSync, mkdirSync as mkdirSync7 } from "fs";
18276
- import { join as join18 } from "path";
18277
- import { homedir as homedir11 } from "os";
16824
+ import { join as join19 } from "path";
16825
+ import { homedir as homedir12 } from "os";
18278
16826
  function write(level, category, message, data) {
18279
16827
  const ts = new Date().toISOString().slice(11, 23);
18280
16828
  const lvl = level.toUpperCase().padEnd(5);
@@ -18290,8 +16838,8 @@ function write(level, category, message, data) {
18290
16838
  }
18291
16839
  var LOG_DIR, LOG_FILE, log;
18292
16840
  var init_log = __esm(() => {
18293
- LOG_DIR = join18(homedir11(), ".scout/pairing");
18294
- LOG_FILE = join18(LOG_DIR, "bridge.log");
16841
+ LOG_DIR = join19(homedir12(), ".scout/pairing");
16842
+ LOG_FILE = join19(LOG_DIR, "bridge.log");
18295
16843
  mkdirSync7(LOG_DIR, { recursive: true });
18296
16844
  log = {
18297
16845
  debug: (cat, msg, data) => write("debug", cat, msg, data),
@@ -18367,11 +16915,11 @@ var init_bridge = __esm(() => {
18367
16915
  });
18368
16916
 
18369
16917
  // ../../apps/desktop/src/core/pairing/runtime/bridge/config.ts
18370
- import { existsSync as existsSync14, readFileSync as readFileSync9 } from "fs";
18371
- import { join as join19 } from "path";
18372
- import { homedir as homedir12 } from "os";
16918
+ import { existsSync as existsSync15, readFileSync as readFileSync9 } from "fs";
16919
+ import { join as join20 } from "path";
16920
+ import { homedir as homedir13 } from "os";
18373
16921
  function loadConfigFile() {
18374
- if (!existsSync14(CONFIG_FILE)) {
16922
+ if (!existsSync15(CONFIG_FILE)) {
18375
16923
  return {};
18376
16924
  }
18377
16925
  try {
@@ -18432,17 +16980,17 @@ var init_config3 = __esm(() => {
18432
16980
  port: 7888,
18433
16981
  secure: true
18434
16982
  };
18435
- CONFIG_DIR = join19(homedir12(), ".scout/pairing");
18436
- CONFIG_FILE = join19(CONFIG_DIR, "config.json");
16983
+ CONFIG_DIR = join20(homedir13(), ".scout/pairing");
16984
+ CONFIG_FILE = join20(CONFIG_DIR, "config.json");
18437
16985
  });
18438
16986
 
18439
16987
  // ../../apps/desktop/src/core/pairing/runtime/bridge/fileserver.ts
18440
16988
  import { isAbsolute as isAbsolute2 } from "path";
18441
- import { homedir as homedir13 } from "os";
16989
+ import { homedir as homedir14 } from "os";
18442
16990
  function isAllowedPath(filePath) {
18443
16991
  if (!isAbsolute2(filePath))
18444
16992
  return false;
18445
- const relToHome = filePath.slice(homedir13().length + 1);
16993
+ const relToHome = filePath.slice(homedir14().length + 1);
18446
16994
  if (relToHome.startsWith(".") && !relToHome.startsWith(".claude") && !relToHome.startsWith(".scout/pairing")) {
18447
16995
  return false;
18448
16996
  }
@@ -18501,16 +17049,16 @@ function serveFile(url) {
18501
17049
  }
18502
17050
  var ALLOWED_ROOTS;
18503
17051
  var init_fileserver = __esm(() => {
18504
- ALLOWED_ROOTS = [homedir13(), "/tmp"];
17052
+ ALLOWED_ROOTS = [homedir14(), "/tmp"];
18505
17053
  });
18506
17054
 
18507
17055
  // ../../apps/desktop/src/server/db-queries.ts
18508
17056
  import { Database } from "bun:sqlite";
18509
- import { homedir as homedir14 } from "os";
18510
- import { join as join20 } from "path";
17057
+ import { homedir as homedir15 } from "os";
17058
+ import { join as join21 } from "path";
18511
17059
  function resolveDbPath() {
18512
- const controlHome = process.env.OPENSCOUT_CONTROL_HOME ?? join20(homedir14(), ".openscout", "control-plane");
18513
- return join20(controlHome, "control-plane.sqlite");
17060
+ const controlHome = process.env.OPENSCOUT_CONTROL_HOME ?? join21(homedir15(), ".openscout", "control-plane");
17061
+ return join21(controlHome, "control-plane.sqlite");
18514
17062
  }
18515
17063
  function db() {
18516
17064
  if (!_db) {
@@ -18752,11 +17300,11 @@ function queryMobileAgentDetail(agentId) {
18752
17300
  }
18753
17301
  var _db = null, HOME;
18754
17302
  var init_db_queries = __esm(() => {
18755
- HOME = homedir14();
17303
+ HOME = homedir15();
18756
17304
  });
18757
17305
 
18758
17306
  // ../../apps/desktop/src/core/mobile/service.ts
18759
- import { basename as basename6, resolve as resolve8 } from "path";
17307
+ import { basename as basename6, resolve as resolve9 } from "path";
18760
17308
  function normalizeTimestamp(value) {
18761
17309
  if (!value)
18762
17310
  return null;
@@ -19145,7 +17693,7 @@ async function createScoutSession(input, currentDirectory, deviceId) {
19145
17693
  if (!rawWorkspaceId) {
19146
17694
  throw new Error(`Invalid workspaceId.`);
19147
17695
  }
19148
- const workspaceRoot = resolve8(rawWorkspaceId);
17696
+ const workspaceRoot = resolve9(rawWorkspaceId);
19149
17697
  const projectName = basename6(workspaceRoot) || workspaceRoot;
19150
17698
  const workspace = {
19151
17699
  id: workspaceRoot,
@@ -19255,17 +17803,17 @@ async function deriveNewAgentName(projectName, branch, harness) {
19255
17803
  }
19256
17804
  async function createGitWorktree(projectRoot, agentName) {
19257
17805
  const { execSync: execSync2 } = await import("child_process");
19258
- const { join: join21 } = await import("path");
19259
- const { mkdirSync: mkdirSync8, existsSync: existsSync15 } = await import("fs");
17806
+ const { join: join22 } = await import("path");
17807
+ const { mkdirSync: mkdirSync8, existsSync: existsSync16 } = await import("fs");
19260
17808
  try {
19261
17809
  execSync2("git rev-parse --git-dir", { cwd: projectRoot, stdio: "pipe" });
19262
17810
  } catch {
19263
17811
  return null;
19264
17812
  }
19265
17813
  const branchName = `scout/${agentName}`;
19266
- const worktreeDir = join21(projectRoot, ".scout-worktrees");
19267
- const worktreePath = join21(worktreeDir, agentName);
19268
- if (existsSync15(worktreePath)) {
17814
+ const worktreeDir = join22(projectRoot, ".scout-worktrees");
17815
+ const worktreePath = join22(worktreeDir, agentName);
17816
+ if (existsSync16(worktreePath)) {
19269
17817
  return { path: worktreePath, branch: branchName };
19270
17818
  }
19271
17819
  mkdirSync8(worktreeDir, { recursive: true });
@@ -19310,8 +17858,8 @@ var init_service5 = __esm(async () => {
19310
17858
  // ../../apps/desktop/src/core/pairing/runtime/bridge/server.ts
19311
17859
  import { readdirSync as readdirSync2, readFileSync as readFileSync10, realpathSync, statSync as statSync3 } from "fs";
19312
17860
  import { execSync as execSync2 } from "child_process";
19313
- import { basename as basename7, isAbsolute as isAbsolute3, join as join21, relative as relative2 } from "path";
19314
- import { homedir as homedir15 } from "os";
17861
+ import { basename as basename7, isAbsolute as isAbsolute3, join as join22, relative as relative2 } from "path";
17862
+ import { homedir as homedir16 } from "os";
19315
17863
  function replaySyncEvents(bridge, sessionId, lastSeq) {
19316
17864
  return bridge.replay(sessionId, lastSeq);
19317
17865
  }
@@ -19765,13 +18313,13 @@ function resolveMobileCurrentDirectory() {
19765
18313
  }
19766
18314
  }
19767
18315
  function resolveWorkspaceRoot(root) {
19768
- const expandedRoot = root.replace(/^~/, homedir15());
18316
+ const expandedRoot = root.replace(/^~/, homedir16());
19769
18317
  return realpathSync(expandedRoot);
19770
18318
  }
19771
18319
  function resolveWorkspacePath(root, requestedPath) {
19772
18320
  const normalizedRoot = resolveWorkspaceRoot(root);
19773
- const expandedPath = requestedPath?.replace(/^~/, homedir15());
19774
- const candidate = expandedPath ? isAbsolute3(expandedPath) ? expandedPath : join21(normalizedRoot, expandedPath) : normalizedRoot;
18321
+ const expandedPath = requestedPath?.replace(/^~/, homedir16());
18322
+ const candidate = expandedPath ? isAbsolute3(expandedPath) ? expandedPath : join22(normalizedRoot, expandedPath) : normalizedRoot;
19775
18323
  const resolvedCandidate = realpathSync(candidate);
19776
18324
  const rel = relative2(normalizedRoot, resolvedCandidate);
19777
18325
  if (rel === "" || !rel.startsWith("..") && !isAbsolute3(rel)) {
@@ -19786,7 +18334,7 @@ function listDirectories(dirPath) {
19786
18334
  continue;
19787
18335
  if (name === "node_modules" || name === ".build" || name === "target")
19788
18336
  continue;
19789
- const fullPath = join21(dirPath, name);
18337
+ const fullPath = join22(dirPath, name);
19790
18338
  try {
19791
18339
  const stat4 = statSync3(fullPath);
19792
18340
  if (!stat4.isDirectory())
@@ -19809,7 +18357,7 @@ function listDirectories(dirPath) {
19809
18357
  return entries.sort((a, b) => a.name.localeCompare(b.name));
19810
18358
  }
19811
18359
  async function discoverSessionFiles(maxAgeDays, limit) {
19812
- const home = homedir15();
18360
+ const home = homedir16();
19813
18361
  const results = [];
19814
18362
  const searchPaths = [
19815
18363
  { pattern: `${home}/.claude/projects`, agent: "claude-code" },
@@ -34717,8 +33265,8 @@ var init_zod = __esm(() => {
34717
33265
  // ../../apps/desktop/src/core/pairing/runtime/bridge/router.ts
34718
33266
  import { readFileSync as readFileSync11, readdirSync as readdirSync3, realpathSync as realpathSync2, statSync as statSync4 } from "fs";
34719
33267
  import { execSync as execSync3 } from "child_process";
34720
- import { basename as basename8, isAbsolute as isAbsolute4, join as join22, relative as relative3 } from "path";
34721
- import { homedir as homedir16 } from "os";
33268
+ import { basename as basename8, isAbsolute as isAbsolute4, join as join23, relative as relative3 } from "path";
33269
+ import { homedir as homedir17 } from "os";
34722
33270
  function resolveMobileCurrentDirectory2() {
34723
33271
  const config2 = resolveConfig();
34724
33272
  const configuredRoot = config2.workspace?.root;
@@ -34731,13 +33279,13 @@ function resolveMobileCurrentDirectory2() {
34731
33279
  }
34732
33280
  }
34733
33281
  function resolveWorkspaceRoot2(root) {
34734
- const expandedRoot = root.replace(/^~/, homedir16());
33282
+ const expandedRoot = root.replace(/^~/, homedir17());
34735
33283
  return realpathSync2(expandedRoot);
34736
33284
  }
34737
33285
  function resolveWorkspacePath2(root, requestedPath) {
34738
33286
  const normalizedRoot = resolveWorkspaceRoot2(root);
34739
- const expandedPath = requestedPath?.replace(/^~/, homedir16());
34740
- const candidate = expandedPath ? isAbsolute4(expandedPath) ? expandedPath : join22(normalizedRoot, expandedPath) : normalizedRoot;
33287
+ const expandedPath = requestedPath?.replace(/^~/, homedir17());
33288
+ const candidate = expandedPath ? isAbsolute4(expandedPath) ? expandedPath : join23(normalizedRoot, expandedPath) : normalizedRoot;
34741
33289
  const resolvedCandidate = realpathSync2(candidate);
34742
33290
  const rel = relative3(normalizedRoot, resolvedCandidate);
34743
33291
  if (rel === "" || !rel.startsWith("..") && !isAbsolute4(rel)) {
@@ -34752,7 +33300,7 @@ function listDirectories2(dirPath) {
34752
33300
  continue;
34753
33301
  if (name === "node_modules" || name === ".build" || name === "target")
34754
33302
  continue;
34755
- const fullPath = join22(dirPath, name);
33303
+ const fullPath = join23(dirPath, name);
34756
33304
  try {
34757
33305
  const stat4 = statSync4(fullPath);
34758
33306
  if (!stat4.isDirectory())
@@ -34791,7 +33339,7 @@ function detectAgent2(filePath) {
34791
33339
  return "unknown";
34792
33340
  }
34793
33341
  async function discoverSessionFiles2(maxAgeDays, limit) {
34794
- const home = homedir16();
33342
+ const home = homedir17();
34795
33343
  const results = [];
34796
33344
  const searchPaths = [
34797
33345
  { pattern: `${home}/.claude/projects`, agent: "claude-code" },
@@ -34873,23 +33421,23 @@ function bridgeEventIterable(bridge, signal) {
34873
33421
  return {
34874
33422
  [Symbol.asyncIterator]() {
34875
33423
  const buffer = [];
34876
- let resolve9 = null;
33424
+ let resolve10 = null;
34877
33425
  let done = false;
34878
33426
  const unsub = bridge.onEvent((event) => {
34879
33427
  if (done)
34880
33428
  return;
34881
33429
  buffer.push(event);
34882
- if (resolve9) {
34883
- resolve9();
34884
- resolve9 = null;
33430
+ if (resolve10) {
33431
+ resolve10();
33432
+ resolve10 = null;
34885
33433
  }
34886
33434
  });
34887
33435
  const cleanup = () => {
34888
33436
  done = true;
34889
33437
  unsub();
34890
- if (resolve9) {
34891
- resolve9();
34892
- resolve9 = null;
33438
+ if (resolve10) {
33439
+ resolve10();
33440
+ resolve10 = null;
34893
33441
  }
34894
33442
  };
34895
33443
  signal?.addEventListener("abort", cleanup, { once: true });
@@ -34902,7 +33450,7 @@ function bridgeEventIterable(bridge, signal) {
34902
33450
  return { done: false, value: buffer.shift() };
34903
33451
  }
34904
33452
  await new Promise((r) => {
34905
- resolve9 = r;
33453
+ resolve10 = r;
34906
33454
  });
34907
33455
  }
34908
33456
  },
@@ -37620,15 +36168,15 @@ function resolveSelfTuple(promise2) {
37620
36168
  return Unpromise.proxy(promise2).then(() => [promise2]);
37621
36169
  }
37622
36170
  function withResolvers() {
37623
- let resolve9;
36171
+ let resolve10;
37624
36172
  let reject;
37625
36173
  const promise2 = new Promise((_resolve, _reject) => {
37626
- resolve9 = _resolve;
36174
+ resolve10 = _resolve;
37627
36175
  reject = _reject;
37628
36176
  });
37629
36177
  return {
37630
36178
  promise: promise2,
37631
- resolve: resolve9,
36179
+ resolve: resolve10,
37632
36180
  reject
37633
36181
  };
37634
36182
  }
@@ -37667,8 +36215,8 @@ function timerResource(ms) {
37667
36215
  return makeResource({ start() {
37668
36216
  if (timer)
37669
36217
  throw new Error("Timer already started");
37670
- const promise2 = new Promise((resolve9) => {
37671
- timer = setTimeout(() => resolve9(disposablePromiseTimerResult), ms);
36218
+ const promise2 = new Promise((resolve10) => {
36219
+ timer = setTimeout(() => resolve10(disposablePromiseTimerResult), ms);
37672
36220
  });
37673
36221
  return promise2;
37674
36222
  } }, () => {
@@ -37717,15 +36265,15 @@ function _takeWithGrace() {
37717
36265
  return _takeWithGrace.apply(this, arguments);
37718
36266
  }
37719
36267
  function createDeferred() {
37720
- let resolve9;
36268
+ let resolve10;
37721
36269
  let reject;
37722
36270
  const promise2 = new Promise((res, rej) => {
37723
- resolve9 = res;
36271
+ resolve10 = res;
37724
36272
  reject = rej;
37725
36273
  });
37726
36274
  return {
37727
36275
  promise: promise2,
37728
- resolve: resolve9,
36276
+ resolve: resolve10,
37729
36277
  reject
37730
36278
  };
37731
36279
  }
@@ -38701,8 +37249,8 @@ var import_objectSpread2$13, jsonContentTypeHandler, formDataContentTypeHandler,
38701
37249
  status: "fulfilled",
38702
37250
  value
38703
37251
  };
38704
- subscribers === null || subscribers === undefined || subscribers.forEach(({ resolve: resolve9 }) => {
38705
- resolve9(value);
37252
+ subscribers === null || subscribers === undefined || subscribers.forEach(({ resolve: resolve10 }) => {
37253
+ resolve10(value);
38706
37254
  });
38707
37255
  });
38708
37256
  if ("catch" in thenReturn)
@@ -39433,14 +37981,14 @@ var init_observable = __esm(() => {
39433
37981
 
39434
37982
  // ../../apps/desktop/src/core/pairing/runtime/bridge/server-trpc.ts
39435
37983
  import { realpathSync as realpathSync3 } from "fs";
39436
- import { homedir as homedir17 } from "os";
37984
+ import { homedir as homedir18 } from "os";
39437
37985
  function resolveCurrentDirectory() {
39438
37986
  try {
39439
37987
  const config2 = resolveConfig();
39440
37988
  const configuredRoot = config2.workspace?.root;
39441
37989
  if (!configuredRoot)
39442
37990
  return process.cwd();
39443
- const expanded = configuredRoot.replace(/^~/, homedir17());
37991
+ const expanded = configuredRoot.replace(/^~/, homedir18());
39444
37992
  return realpathSync3(expanded);
39445
37993
  } catch {
39446
37994
  return process.cwd();
@@ -39558,8 +38106,8 @@ function startBridgeServerTRPC(options) {
39558
38106
  }
39559
38107
  const iterable = isObservable(result) ? observableToAsyncIterable(result, abortController.signal) : result;
39560
38108
  const iterator = iterable[Symbol.asyncIterator]();
39561
- const abortPromise = new Promise((resolve9) => {
39562
- abortController.signal.addEventListener("abort", () => resolve9("abort"), {
38109
+ const abortPromise = new Promise((resolve10) => {
38110
+ abortController.signal.addEventListener("abort", () => resolve10("abort"), {
39563
38111
  once: true
39564
38112
  });
39565
38113
  });
@@ -39856,7 +38404,7 @@ var init_server_trpc = __esm(async () => {
39856
38404
  });
39857
38405
 
39858
38406
  // ../../apps/desktop/src/core/pairing/runtime/runtime.ts
39859
- import { homedir as homedir18 } from "os";
38407
+ import { homedir as homedir19 } from "os";
39860
38408
  function createPairingAdapterRegistry(configAdapters) {
39861
38409
  const adapters = {
39862
38410
  "claude-code": createAdapter,
@@ -39933,7 +38481,7 @@ async function autoStartConfiguredSessions(bridge, sessions3) {
39933
38481
  try {
39934
38482
  const session = await bridge.createSession(entry.adapter, {
39935
38483
  name: entry.name,
39936
- cwd: entry.cwd?.replace(/^~/, homedir18()),
38484
+ cwd: entry.cwd?.replace(/^~/, homedir19()),
39937
38485
  options: entry.options
39938
38486
  });
39939
38487
  console.log(`[bridge] session started: ${session.name} (${entry.adapter})`);
@@ -40204,11 +38752,11 @@ var BRIDGE_ABSENCE_GRACE_MS = 30000, ROOM_IDLE_TIMEOUT_MS = 60000;
40204
38752
 
40205
38753
  // ../../apps/desktop/src/core/pairing/runtime/relay-runtime.ts
40206
38754
  import { execSync as execSync4 } from "child_process";
40207
- import { existsSync as existsSync15, mkdirSync as mkdirSync9, readdirSync as readdirSync4 } from "fs";
40208
- import { homedir as homedir19 } from "os";
40209
- import { join as join23 } from "path";
38755
+ import { existsSync as existsSync16, mkdirSync as mkdirSync9, readdirSync as readdirSync4 } from "fs";
38756
+ import { homedir as homedir20 } from "os";
38757
+ import { join as join24 } from "path";
40210
38758
  function findStoredCerts() {
40211
- if (!existsSync15(PAIRING_DIR2)) {
38759
+ if (!existsSync16(PAIRING_DIR2)) {
40212
38760
  return null;
40213
38761
  }
40214
38762
  try {
@@ -40222,8 +38770,8 @@ function findStoredCerts() {
40222
38770
  return null;
40223
38771
  }
40224
38772
  return {
40225
- cert: join23(PAIRING_DIR2, certFile),
40226
- key: join23(PAIRING_DIR2, keyFile)
38773
+ cert: join24(PAIRING_DIR2, certFile),
38774
+ key: join24(PAIRING_DIR2, keyFile)
40227
38775
  };
40228
38776
  } catch {
40229
38777
  return null;
@@ -40244,8 +38792,8 @@ function getTailscaleHostname() {
40244
38792
  }
40245
38793
  function generateTailscaleCerts(hostname5) {
40246
38794
  mkdirSync9(PAIRING_DIR2, { recursive: true });
40247
- const certPath = join23(PAIRING_DIR2, `${hostname5}.crt`);
40248
- const keyPath = join23(PAIRING_DIR2, `${hostname5}.key`);
38795
+ const certPath = join24(PAIRING_DIR2, `${hostname5}.crt`);
38796
+ const keyPath = join24(PAIRING_DIR2, `${hostname5}.key`);
40249
38797
  try {
40250
38798
  pairingLog.info("relay", "generating tailscale TLS cert", { hostname: hostname5 });
40251
38799
  execSync4(`tailscale cert --cert-file "${certPath}" --key-file "${keyPath}" "${hostname5}"`, {
@@ -40261,8 +38809,8 @@ function generateTailscaleCerts(hostname5) {
40261
38809
  }
40262
38810
  function generateSelfSignedCert(hostname5) {
40263
38811
  mkdirSync9(PAIRING_DIR2, { recursive: true });
40264
- const certPath = join23(PAIRING_DIR2, `${hostname5}.crt`);
40265
- const keyPath = join23(PAIRING_DIR2, `${hostname5}.key`);
38812
+ const certPath = join24(PAIRING_DIR2, `${hostname5}.crt`);
38813
+ const keyPath = join24(PAIRING_DIR2, `${hostname5}.key`);
40266
38814
  try {
40267
38815
  execSync4(`openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 ` + `-keyout "${keyPath}" -out "${certPath}" -days 365 -nodes ` + `-subj "/CN=${hostname5}" -addext "subjectAltName=DNS:${hostname5}"`, {
40268
38816
  stdio: ["pipe", "pipe", "pipe"],
@@ -40325,7 +38873,7 @@ function startManagedRelay(port = 7889) {
40325
38873
  var PAIRING_DIR2;
40326
38874
  var init_relay_runtime = __esm(() => {
40327
38875
  init_log2();
40328
- PAIRING_DIR2 = join23(homedir19(), ".scout/pairing");
38876
+ PAIRING_DIR2 = join24(homedir20(), ".scout/pairing");
40329
38877
  });
40330
38878
 
40331
38879
  // ../../node_modules/.bun/uqr@0.1.3/node_modules/uqr/dist/index.mjs
@@ -41190,8 +39738,8 @@ async function runPairCommand(context, args) {
41190
39738
  process.on("SIGINT", handleSignal);
41191
39739
  process.on("SIGTERM", handleSignal);
41192
39740
  try {
41193
- await new Promise((resolve9) => {
41194
- controller.signal.addEventListener("abort", () => resolve9(), { once: true });
39741
+ await new Promise((resolve10) => {
39742
+ controller.signal.addEventListener("abort", () => resolve10(), { once: true });
41195
39743
  });
41196
39744
  } finally {
41197
39745
  process.off("SIGINT", handleSignal);
@@ -41254,39 +39802,6 @@ var init_runtimes = __esm(() => {
41254
39802
  init_service3();
41255
39803
  });
41256
39804
 
41257
- // ../../apps/desktop/src/cli/commands/send.ts
41258
- var exports_send = {};
41259
- __export(exports_send, {
41260
- runSendCommand: () => runSendCommand
41261
- });
41262
- async function runSendCommand(context, args) {
41263
- const options = parseSendCommandOptions(args, defaultScoutContextDirectory(context));
41264
- const currentDirectory = options.currentDirectory ?? defaultScoutContextDirectory(context);
41265
- const senderId = await resolveScoutSenderId(options.agentName, currentDirectory);
41266
- const result = await sendScoutMessage({
41267
- senderId,
41268
- body: options.message,
41269
- channel: options.channel,
41270
- shouldSpeak: options.shouldSpeak,
41271
- executionHarness: parseScoutHarness(options.harness),
41272
- currentDirectory: options.currentDirectory
41273
- });
41274
- if (!result.usedBroker) {
41275
- throw new Error("broker is not reachable");
41276
- }
41277
- context.output.writeValue({
41278
- message: options.message,
41279
- invokedTargets: result.invokedTargets,
41280
- unresolvedTargets: result.unresolvedTargets
41281
- }, renderScoutMessagePostResult);
41282
- }
41283
- var init_send = __esm(async () => {
41284
- init_context();
41285
- init_options();
41286
- init_broker();
41287
- await init_service();
41288
- });
41289
-
41290
39805
  // ../../apps/desktop/src/cli/commands/server.ts
41291
39806
  var exports_server = {};
41292
39807
  __export(exports_server, {
@@ -41297,9 +39812,9 @@ __export(exports_server, {
41297
39812
  normalizeServerOpenPath: () => normalizeServerOpenPath
41298
39813
  });
41299
39814
  import { spawn as spawn5 } from "child_process";
41300
- import { existsSync as existsSync16 } from "fs";
41301
- import { dirname as dirname10, join as join24, resolve as resolve9 } from "path";
41302
- import { fileURLToPath as fileURLToPath7 } from "url";
39815
+ import { existsSync as existsSync17 } from "fs";
39816
+ import { dirname as dirname11, join as join25, resolve as resolve10 } from "path";
39817
+ import { fileURLToPath as fileURLToPath8 } from "url";
41303
39818
  function renderServerCommandHelp() {
41304
39819
  return [
41305
39820
  "scout server \u2014 desktop web UI (Bun runtime)",
@@ -41332,25 +39847,25 @@ function renderServerCommandHelp() {
41332
39847
  `);
41333
39848
  }
41334
39849
  function resolveScoutWebServerEntry() {
41335
- const mainDir = dirname10(fileURLToPath7(import.meta.url));
41336
- const bundled = join24(mainDir, "scout-web-server.mjs");
41337
- if (existsSync16(bundled)) {
39850
+ const mainDir = dirname11(fileURLToPath8(import.meta.url));
39851
+ const bundled = join25(mainDir, "scout-web-server.mjs");
39852
+ if (existsSync17(bundled)) {
41338
39853
  return bundled;
41339
39854
  }
41340
- const source = fileURLToPath7(new URL("../../server/index.ts", import.meta.url));
41341
- if (existsSync16(source)) {
39855
+ const source = fileURLToPath8(new URL("../../server/index.ts", import.meta.url));
39856
+ if (existsSync17(source)) {
41342
39857
  return source;
41343
39858
  }
41344
39859
  throw new ScoutCliError("Could not find Scout web server entry. Rebuild @openscout/scout or run from the OpenScout repository.");
41345
39860
  }
41346
39861
  function resolveScoutControlPlaneWebServerEntry() {
41347
- const mainDir = dirname10(fileURLToPath7(import.meta.url));
41348
- const bundled = join24(mainDir, "scout-control-plane-web.mjs");
41349
- if (existsSync16(bundled)) {
39862
+ const mainDir = dirname11(fileURLToPath8(import.meta.url));
39863
+ const bundled = join25(mainDir, "scout-control-plane-web.mjs");
39864
+ if (existsSync17(bundled)) {
41350
39865
  return bundled;
41351
39866
  }
41352
- const source = fileURLToPath7(new URL("../../server/control-plane-index.ts", import.meta.url));
41353
- if (existsSync16(source)) {
39867
+ const source = fileURLToPath8(new URL("../../server/control-plane-index.ts", import.meta.url));
39868
+ if (existsSync17(source)) {
41354
39869
  return source;
41355
39870
  }
41356
39871
  throw new ScoutCliError("Could not find Scout control-plane web server entry. Rebuild @openscout/scout or run from the OpenScout repository.");
@@ -41424,10 +39939,10 @@ function parseServerFlags(args) {
41424
39939
  return { env, openPath };
41425
39940
  }
41426
39941
  function resolveBundledStaticClientRoot(entry, mode) {
41427
- const entryDir = dirname10(entry);
41428
- const clientDirectory = mode === "control-plane" ? join24(entryDir, "control-plane-client") : join24(entryDir, "client");
41429
- const indexPath = join24(clientDirectory, "index.html");
41430
- return existsSync16(indexPath) ? clientDirectory : null;
39942
+ const entryDir = dirname11(entry);
39943
+ const clientDirectory = mode === "control-plane" ? join25(entryDir, "control-plane-client") : join25(entryDir, "client");
39944
+ const indexPath = join25(clientDirectory, "index.html");
39945
+ return existsSync17(indexPath) ? clientDirectory : null;
41431
39946
  }
41432
39947
  function buildMergedServerEnv(entry, mode, flagEnv) {
41433
39948
  const bundledStaticClientRoot = resolveBundledStaticClientRoot(entry, mode);
@@ -41493,7 +40008,7 @@ function resolveServerPort(env) {
41493
40008
  return port;
41494
40009
  }
41495
40010
  function resolveExpectedCurrentDirectory(env) {
41496
- return resolve9(env.OPENSCOUT_SETUP_CWD?.trim() || process.cwd());
40011
+ return resolve10(env.OPENSCOUT_SETUP_CWD?.trim() || process.cwd());
41497
40012
  }
41498
40013
  function renderModeLabel(mode) {
41499
40014
  return mode === "control-plane" ? "Scout control plane" : "Scout";
@@ -41617,7 +40132,7 @@ async function waitForScoutServer(port, mode, expectedCurrentDirectory) {
41617
40132
  while (Date.now() < deadline) {
41618
40133
  const probe = await probeScoutServer(port);
41619
40134
  if (probe.status === "healthy") {
41620
- const actualCurrentDirectory = resolve9(probe.health.currentDirectory);
40135
+ const actualCurrentDirectory = resolve10(probe.health.currentDirectory);
41621
40136
  if (probe.health.surface !== mode) {
41622
40137
  throw new ScoutCliError(`port ${port} is serving Scout ${renderSurfaceLabel(probe.health.surface)}, not ${renderModeLabel(mode)}.`);
41623
40138
  }
@@ -41639,7 +40154,7 @@ async function openScoutServer(options) {
41639
40154
  const browserUrl = new URL(normalizeServerOpenPath(options.openPath), `http://127.0.0.1:${port}`).toString();
41640
40155
  const probe = await probeScoutServer(port);
41641
40156
  if (probe.status === "healthy") {
41642
- const actualCurrentDirectory = resolve9(probe.health.currentDirectory);
40157
+ const actualCurrentDirectory = resolve10(probe.health.currentDirectory);
41643
40158
  if (probe.health.surface !== options.mode) {
41644
40159
  throw new ScoutCliError(`port ${port} is already serving Scout ${renderSurfaceLabel(probe.health.surface)}, not ${renderModeLabel(options.mode)}.`);
41645
40160
  }
@@ -41720,8 +40235,8 @@ var init_server2 = __esm(() => {
41720
40235
  });
41721
40236
 
41722
40237
  // ../../apps/desktop/src/cli/commands/setup.ts
41723
- var exports_setup2 = {};
41724
- __export(exports_setup2, {
40238
+ var exports_setup = {};
40239
+ __export(exports_setup, {
41725
40240
  runSetupCommand: () => runSetupCommand
41726
40241
  });
41727
40242
  async function runSetupCommand(context, args) {
@@ -41743,7 +40258,7 @@ __export(exports_speak, {
41743
40258
  async function runSpeakCommand(context, args) {
41744
40259
  const options = parseSendCommandOptions(args, defaultScoutContextDirectory(context));
41745
40260
  const currentDirectory = options.currentDirectory ?? defaultScoutContextDirectory(context);
41746
- const senderId = await resolveScoutSenderId(options.agentName, currentDirectory);
40261
+ const senderId = await resolveScoutSenderId(options.agentName, currentDirectory, context.env);
41747
40262
  const config3 = await loadScoutRelayConfig();
41748
40263
  const voice = getScoutVoiceForChannel(config3, "voice");
41749
40264
  await acquireScoutOnAir(senderId);
@@ -41766,6 +40281,9 @@ async function runSpeakCommand(context, args) {
41766
40281
  if (!result.usedBroker) {
41767
40282
  throw new Error("broker is not reachable");
41768
40283
  }
40284
+ if (result.unresolvedTargets.length > 0) {
40285
+ throw new Error(formatScoutSendRoutingError(result.unresolvedTargets));
40286
+ }
41769
40287
  context.output.writeValue({
41770
40288
  message: options.message,
41771
40289
  invokedTargets: result.invokedTargets,
@@ -41776,7 +40294,10 @@ var init_speak = __esm(async () => {
41776
40294
  init_context();
41777
40295
  init_options();
41778
40296
  init_broker();
41779
- await init_service();
40297
+ await __promiseAll([
40298
+ init_service(),
40299
+ init_send()
40300
+ ]);
41780
40301
  });
41781
40302
 
41782
40303
  // ../../node_modules/.bun/@opentui+core@0.1.96+a7e4efcb39f2fc50/node_modules/@opentui/core/assets/javascript/highlights.scm
@@ -41828,11 +40349,11 @@ import { EventEmitter } from "events";
41828
40349
  import { Buffer as Buffer2 } from "buffer";
41829
40350
  import { Buffer as Buffer3 } from "buffer";
41830
40351
  import { EventEmitter as EventEmitter2 } from "events";
41831
- import { resolve as resolve10, dirname as dirname11 } from "path";
41832
- import { fileURLToPath as fileURLToPath8 } from "url";
40352
+ import { resolve as resolve11, dirname as dirname12 } from "path";
40353
+ import { fileURLToPath as fileURLToPath9 } from "url";
41833
40354
  import { resolve as resolve22, isAbsolute as isAbsolute5, parse as parse6 } from "path";
41834
- import { existsSync as existsSync17 } from "fs";
41835
- import { basename as basename9, join as join25 } from "path";
40355
+ import { existsSync as existsSync18 } from "fs";
40356
+ import { basename as basename9, join as join26 } from "path";
41836
40357
  import os from "os";
41837
40358
  import path2 from "path";
41838
40359
  import { EventEmitter as EventEmitter3 } from "events";
@@ -44964,13 +43485,13 @@ class DebounceController {
44964
43485
  }
44965
43486
  debounce(id, ms, fn) {
44966
43487
  const scopeMap = TIMERS_MAP.get(this.scopeId);
44967
- return new Promise((resolve12, reject) => {
43488
+ return new Promise((resolve13, reject) => {
44968
43489
  if (scopeMap.has(id)) {
44969
43490
  clearTimeout(scopeMap.get(id));
44970
43491
  }
44971
43492
  const timerId = setTimeout(() => {
44972
43493
  try {
44973
- resolve12(fn());
43494
+ resolve13(fn());
44974
43495
  } catch (error48) {
44975
43496
  reject(error48);
44976
43497
  }
@@ -45060,25 +43581,25 @@ function getParsers() {
45060
43581
  filetype: "javascript",
45061
43582
  aliases: ["javascriptreact"],
45062
43583
  queries: {
45063
- highlights: [resolve10(dirname11(fileURLToPath8(import.meta.url)), highlights_default)]
43584
+ highlights: [resolve11(dirname12(fileURLToPath9(import.meta.url)), highlights_default)]
45064
43585
  },
45065
- wasm: resolve10(dirname11(fileURLToPath8(import.meta.url)), tree_sitter_javascript_default)
43586
+ wasm: resolve11(dirname12(fileURLToPath9(import.meta.url)), tree_sitter_javascript_default)
45066
43587
  },
45067
43588
  {
45068
43589
  filetype: "typescript",
45069
43590
  aliases: ["typescriptreact"],
45070
43591
  queries: {
45071
- highlights: [resolve10(dirname11(fileURLToPath8(import.meta.url)), highlights_default2)]
43592
+ highlights: [resolve11(dirname12(fileURLToPath9(import.meta.url)), highlights_default2)]
45072
43593
  },
45073
- wasm: resolve10(dirname11(fileURLToPath8(import.meta.url)), tree_sitter_typescript_default)
43594
+ wasm: resolve11(dirname12(fileURLToPath9(import.meta.url)), tree_sitter_typescript_default)
45074
43595
  },
45075
43596
  {
45076
43597
  filetype: "markdown",
45077
43598
  queries: {
45078
- highlights: [resolve10(dirname11(fileURLToPath8(import.meta.url)), highlights_default3)],
45079
- injections: [resolve10(dirname11(fileURLToPath8(import.meta.url)), injections_default)]
43599
+ highlights: [resolve11(dirname12(fileURLToPath9(import.meta.url)), highlights_default3)],
43600
+ injections: [resolve11(dirname12(fileURLToPath9(import.meta.url)), injections_default)]
45080
43601
  },
45081
- wasm: resolve10(dirname11(fileURLToPath8(import.meta.url)), tree_sitter_markdown_default),
43602
+ wasm: resolve11(dirname12(fileURLToPath9(import.meta.url)), tree_sitter_markdown_default),
45082
43603
  injectionMapping: {
45083
43604
  nodeTypes: {
45084
43605
  inline: "markdown_inline",
@@ -45101,16 +43622,16 @@ function getParsers() {
45101
43622
  {
45102
43623
  filetype: "markdown_inline",
45103
43624
  queries: {
45104
- highlights: [resolve10(dirname11(fileURLToPath8(import.meta.url)), highlights_default4)]
43625
+ highlights: [resolve11(dirname12(fileURLToPath9(import.meta.url)), highlights_default4)]
45105
43626
  },
45106
- wasm: resolve10(dirname11(fileURLToPath8(import.meta.url)), tree_sitter_markdown_inline_default)
43627
+ wasm: resolve11(dirname12(fileURLToPath9(import.meta.url)), tree_sitter_markdown_inline_default)
45107
43628
  },
45108
43629
  {
45109
43630
  filetype: "zig",
45110
43631
  queries: {
45111
- highlights: [resolve10(dirname11(fileURLToPath8(import.meta.url)), highlights_default5)]
43632
+ highlights: [resolve11(dirname12(fileURLToPath9(import.meta.url)), highlights_default5)]
45112
43633
  },
45113
- wasm: resolve10(dirname11(fileURLToPath8(import.meta.url)), tree_sitter_zig_default)
43634
+ wasm: resolve11(dirname12(fileURLToPath9(import.meta.url)), tree_sitter_zig_default)
45114
43635
  }
45115
43636
  ];
45116
43637
  }
@@ -45123,7 +43644,7 @@ function getBunfsRootPath() {
45123
43644
  return process.platform === "win32" ? "B:\\~BUN\\root" : "/$bunfs/root";
45124
43645
  }
45125
43646
  function normalizeBunfsPath(fileName) {
45126
- return join25(getBunfsRootPath(), basename9(fileName));
43647
+ return join26(getBunfsRootPath(), basename9(fileName));
45127
43648
  }
45128
43649
  function addDefaultParsers(parsers) {
45129
43650
  for (const parser of parsers) {
@@ -56045,7 +54566,7 @@ var init_index_vy1rm1x3 = __esm(async () => {
56045
54566
  worker_path = this.options.workerPath;
56046
54567
  } else {
56047
54568
  worker_path = new URL("./parser.worker.js", import.meta.url).href;
56048
- if (!existsSync17(resolve22(import.meta.dirname, "parser.worker.js"))) {
54569
+ if (!existsSync18(resolve22(import.meta.dirname, "parser.worker.js"))) {
56049
54570
  worker_path = new URL("./parser.worker.ts", import.meta.url).href;
56050
54571
  }
56051
54572
  }
@@ -74346,14 +72867,14 @@ See https://react.dev/link/invalid-hook-call for tips about how to debug and fix
74346
72867
  prevActScopeDepth !== actScopeDepth - 1 && console.error("You seem to have overlapping act() calls, this is not supported. Be sure to await previous act() calls before making a new one. ");
74347
72868
  actScopeDepth = prevActScopeDepth;
74348
72869
  }
74349
- function recursivelyFlushAsyncActWork(returnValue, resolve12, reject) {
72870
+ function recursivelyFlushAsyncActWork(returnValue, resolve13, reject) {
74350
72871
  var queue = ReactSharedInternals.actQueue;
74351
72872
  if (queue !== null)
74352
72873
  if (queue.length !== 0)
74353
72874
  try {
74354
72875
  flushActQueue(queue);
74355
72876
  enqueueTask(function() {
74356
- return recursivelyFlushAsyncActWork(returnValue, resolve12, reject);
72877
+ return recursivelyFlushAsyncActWork(returnValue, resolve13, reject);
74357
72878
  });
74358
72879
  return;
74359
72880
  } catch (error48) {
@@ -74361,7 +72882,7 @@ See https://react.dev/link/invalid-hook-call for tips about how to debug and fix
74361
72882
  }
74362
72883
  else
74363
72884
  ReactSharedInternals.actQueue = null;
74364
- 0 < ReactSharedInternals.thrownErrors.length ? (queue = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, reject(queue)) : resolve12(returnValue);
72885
+ 0 < ReactSharedInternals.thrownErrors.length ? (queue = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, reject(queue)) : resolve13(returnValue);
74365
72886
  }
74366
72887
  function flushActQueue(queue) {
74367
72888
  if (!isFlushing) {
@@ -74537,14 +73058,14 @@ See https://react.dev/link/invalid-hook-call for tips about how to debug and fix
74537
73058
  didAwaitActCall || didWarnNoAwaitAct || (didWarnNoAwaitAct = true, console.error("You called act(async () => ...) without await. This could lead to unexpected testing behaviour, interleaving multiple act calls and mixing their scopes. You should - await act(async () => ...);"));
74538
73059
  });
74539
73060
  return {
74540
- then: function(resolve12, reject) {
73061
+ then: function(resolve13, reject) {
74541
73062
  didAwaitActCall = true;
74542
73063
  thenable.then(function(returnValue) {
74543
73064
  popActScope(prevActQueue, prevActScopeDepth);
74544
73065
  if (prevActScopeDepth === 0) {
74545
73066
  try {
74546
73067
  flushActQueue(queue), enqueueTask(function() {
74547
- return recursivelyFlushAsyncActWork(returnValue, resolve12, reject);
73068
+ return recursivelyFlushAsyncActWork(returnValue, resolve13, reject);
74548
73069
  });
74549
73070
  } catch (error$0) {
74550
73071
  ReactSharedInternals.thrownErrors.push(error$0);
@@ -74555,7 +73076,7 @@ See https://react.dev/link/invalid-hook-call for tips about how to debug and fix
74555
73076
  reject(_thrownError);
74556
73077
  }
74557
73078
  } else
74558
- resolve12(returnValue);
73079
+ resolve13(returnValue);
74559
73080
  }, function(error48) {
74560
73081
  popActScope(prevActQueue, prevActScopeDepth);
74561
73082
  0 < ReactSharedInternals.thrownErrors.length ? (error48 = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, reject(error48)) : reject(error48);
@@ -74571,11 +73092,11 @@ See https://react.dev/link/invalid-hook-call for tips about how to debug and fix
74571
73092
  if (0 < ReactSharedInternals.thrownErrors.length)
74572
73093
  throw callback = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, callback;
74573
73094
  return {
74574
- then: function(resolve12, reject) {
73095
+ then: function(resolve13, reject) {
74575
73096
  didAwaitActCall = true;
74576
73097
  prevActScopeDepth === 0 ? (ReactSharedInternals.actQueue = queue, enqueueTask(function() {
74577
- return recursivelyFlushAsyncActWork(returnValue$jscomp$0, resolve12, reject);
74578
- })) : resolve12(returnValue$jscomp$0);
73098
+ return recursivelyFlushAsyncActWork(returnValue$jscomp$0, resolve13, reject);
73099
+ })) : resolve13(returnValue$jscomp$0);
74579
73100
  }
74580
73101
  };
74581
73102
  };
@@ -77056,8 +75577,8 @@ It can also happen if the client has a browser extension installed which messes
77056
75577
  currentEntangledActionThenable = {
77057
75578
  status: "pending",
77058
75579
  value: undefined,
77059
- then: function(resolve12) {
77060
- entangledListeners.push(resolve12);
75580
+ then: function(resolve13) {
75581
+ entangledListeners.push(resolve13);
77061
75582
  }
77062
75583
  };
77063
75584
  }
@@ -77081,8 +75602,8 @@ It can also happen if the client has a browser extension installed which messes
77081
75602
  status: "pending",
77082
75603
  value: null,
77083
75604
  reason: null,
77084
- then: function(resolve12) {
77085
- listeners.push(resolve12);
75605
+ then: function(resolve13) {
75606
+ listeners.push(resolve13);
77086
75607
  }
77087
75608
  };
77088
75609
  thenable.then(function() {
@@ -103064,14 +101585,14 @@ async function runScoutMonitorApp(options) {
103064
101585
  }
103065
101586
  const renderer = await createCliRenderer();
103066
101587
  let closed = false;
103067
- await new Promise((resolve12) => {
101588
+ await new Promise((resolve13) => {
103068
101589
  const close = () => {
103069
101590
  if (closed) {
103070
101591
  return;
103071
101592
  }
103072
101593
  closed = true;
103073
101594
  renderer.destroy();
103074
- resolve12();
101595
+ resolve13();
103075
101596
  };
103076
101597
  createRoot(renderer).render(/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ScoutMonitorApp, {
103077
101598
  currentDirectory: options.currentDirectory,
@@ -103119,8 +101640,8 @@ var exports_up = {};
103119
101640
  __export(exports_up, {
103120
101641
  runUpCommand: () => runUpCommand
103121
101642
  });
103122
- import { existsSync as existsSync18 } from "fs";
103123
- import { resolve as resolve12 } from "path";
101643
+ import { existsSync as existsSync19 } from "fs";
101644
+ import { resolve as resolve13 } from "path";
103124
101645
  function looksLikePath(value) {
103125
101646
  return value.includes("/") || value.startsWith(".") || value.startsWith("~");
103126
101647
  }
@@ -103168,8 +101689,8 @@ async function runUpCommand(context, args) {
103168
101689
  throw new ScoutCliError("usage: scout up <name|path> [--name <alias>] [--harness <claude|codex>]");
103169
101690
  }
103170
101691
  let projectPath;
103171
- if (looksLikePath(target) || existsSync18(resolve12(target))) {
103172
- projectPath = resolve12(target);
101692
+ if (looksLikePath(target) || existsSync19(resolve13(target))) {
101693
+ projectPath = resolve13(target);
103173
101694
  } else {
103174
101695
  const resolved = await resolveLocalAgentByName(target);
103175
101696
  if (!resolved) {
@@ -103207,10 +101728,9 @@ async function runWatchCommand(context, args) {
103207
101728
  process.on("SIGINT", shutdown);
103208
101729
  try {
103209
101730
  if (context.output.mode === "plain") {
103210
- context.stdout(`Watching ${options.channel?.trim() || "shared"} as ${resolveScoutAgentName(options.agentName)}`);
101731
+ context.stdout(`Watching ${options.channel?.trim() || "shared"}`);
103211
101732
  }
103212
101733
  await watchScoutMessages({
103213
- agentId: resolveScoutAgentName(options.agentName),
103214
101734
  channel: options.channel,
103215
101735
  signal: controller.signal,
103216
101736
  onMessage(message) {
@@ -103251,12 +101771,10 @@ __export(exports_whoami, {
103251
101771
  runWhoAmICommand: () => runWhoAmICommand
103252
101772
  });
103253
101773
  async function loadScoutWhoAmIReport(context, currentDirectory) {
103254
- const askWatchId = resolveScoutAgentName(null);
103255
- const sendSpeakId = await resolveScoutSenderId(null, currentDirectory);
101774
+ const defaultSenderId = await resolveScoutSenderId(null, currentDirectory, context.env);
103256
101775
  const projectRoot = await findNearestProjectRoot(currentDirectory);
103257
101776
  return {
103258
- askWatchId,
103259
- sendSpeakId,
101777
+ defaultSenderId,
103260
101778
  envAgent: context.env.OPENSCOUT_AGENT?.trim() || null,
103261
101779
  currentDirectory,
103262
101780
  projectRoot,
@@ -103265,8 +101783,7 @@ async function loadScoutWhoAmIReport(context, currentDirectory) {
103265
101783
  }
103266
101784
  function renderScoutWhoAmIReport(report) {
103267
101785
  const lines = [
103268
- `Ask/Watch: ${report.askWatchId}`,
103269
- `Send/Speak: ${report.sendSpeakId}`,
101786
+ `Default Sender: ${report.defaultSenderId}`,
103270
101787
  `Current Directory: ${report.currentDirectory}`,
103271
101788
  `Broker: ${report.brokerUrl}`
103272
101789
  ];
@@ -103352,6 +101869,8 @@ async function loadScoutCommandHandler(name) {
103352
101869
  return (await init_env().then(() => exports_env)).runEnvCommand;
103353
101870
  case "latest":
103354
101871
  return (await init_latest().then(() => exports_latest)).runLatestCommand;
101872
+ case "menu":
101873
+ return (await Promise.resolve().then(() => (init_menu(), exports_menu))).runMenuCommand;
103355
101874
  case "mesh":
103356
101875
  return (await init_mesh().then(() => exports_mesh)).runMeshCommand;
103357
101876
  case "pair":
@@ -103367,7 +101886,7 @@ async function loadScoutCommandHandler(name) {
103367
101886
  case "server":
103368
101887
  return (await Promise.resolve().then(() => (init_server2(), exports_server))).runServerCommand;
103369
101888
  case "setup":
103370
- return (await Promise.resolve().then(() => (init_setup2(), exports_setup2))).runSetupCommand;
101889
+ return (await Promise.resolve().then(() => (init_setup2(), exports_setup))).runSetupCommand;
103371
101890
  case "speak":
103372
101891
  return (await init_speak().then(() => exports_speak)).runSpeakCommand;
103373
101892
  case "tui":
@@ -103405,6 +101924,7 @@ var SCOUT_COMMANDS = [
103405
101924
  { name: "down", summary: "Stop one or all local agents" },
103406
101925
  { name: "ps", summary: "List configured local agents" },
103407
101926
  { name: "restart", summary: "Restart configured local agents" },
101927
+ { name: "menu", summary: "Launch the OpenScout macOS menu bar app" },
103408
101928
  { name: "config", summary: "View or set user config (name, etc.)" },
103409
101929
  { name: "mesh", summary: "Mesh status and diagnostics" },
103410
101930
  { name: "pair", summary: "Pair a companion device via QR" },
@@ -103461,6 +101981,7 @@ function renderScoutHelp(version2 = "0.2.18") {
103461
101981
  " scout whoami",
103462
101982
  " scout who",
103463
101983
  " scout latest",
101984
+ " scout menu",
103464
101985
  " scout server open",
103465
101986
  "",
103466
101987
  "Addressing:",