@openscout/scout 0.2.46 → 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/README.md +58 -3
- package/dist/client/assets/index-CA2ASaSK.css +1 -0
- package/dist/client/index.html +2 -2
- package/dist/control-plane-client/assets/addon-fit-DX4qG4td.js +1 -0
- package/dist/control-plane-client/assets/addon-webgl-DCtw1yLn.js +64 -0
- package/dist/control-plane-client/assets/{arc.es-CehM6B37.js → arc.es-DndjiskC.js} +1 -1
- package/dist/control-plane-client/assets/index-CCQvN8TG.css +1 -0
- package/dist/control-plane-client/assets/index-DlKOe-t6.js +140 -0
- package/dist/control-plane-client/assets/index-TVkH_WDG.js +1 -0
- package/dist/control-plane-client/assets/xterm-B-qIQCd3.js +16 -0
- package/dist/control-plane-client/index.html +2 -2
- package/dist/main.mjs +1034 -2071
- package/dist/pair-supervisor.mjs +12519 -12609
- package/dist/scout-control-plane-web.mjs +9728 -9828
- package/dist/scout-web-server.mjs +8792 -8897
- package/package.json +2 -2
- package/dist/client/assets/index-BIhZnptE.css +0 -1
- package/dist/control-plane-client/assets/index-C3R8grI3.css +0 -1
- package/dist/control-plane-client/assets/index-D17d1jzn.js +0 -9
- /package/dist/client/assets/{index-Dz8OkaKF.js → index-DAPDqcsj.js} +0 -0
package/dist/main.mjs
CHANGED
|
@@ -382,6 +382,53 @@ function parseWatchCommandOptions(args, defaultCurrentDirectory) {
|
|
|
382
382
|
channel
|
|
383
383
|
};
|
|
384
384
|
}
|
|
385
|
+
function parseLatestCommandOptions(args, defaultCurrentDirectory) {
|
|
386
|
+
const parsed = parseContextRootPrefix(args, defaultCurrentDirectory);
|
|
387
|
+
let agentId;
|
|
388
|
+
let actorId;
|
|
389
|
+
let conversationId;
|
|
390
|
+
let limit = 12;
|
|
391
|
+
for (let index = 0;index < parsed.args.length; index += 1) {
|
|
392
|
+
const current = parsed.args[index] ?? "";
|
|
393
|
+
if (current === "--agent" || current.startsWith("--agent=")) {
|
|
394
|
+
const value = parseFlagValue(parsed.args, index, "--agent");
|
|
395
|
+
agentId = value.value;
|
|
396
|
+
index = value.nextIndex;
|
|
397
|
+
continue;
|
|
398
|
+
}
|
|
399
|
+
if (current === "--actor" || current.startsWith("--actor=")) {
|
|
400
|
+
const value = parseFlagValue(parsed.args, index, "--actor");
|
|
401
|
+
actorId = value.value;
|
|
402
|
+
index = value.nextIndex;
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
if (current === "--conversation" || current.startsWith("--conversation=")) {
|
|
406
|
+
const value = parseFlagValue(parsed.args, index, "--conversation");
|
|
407
|
+
conversationId = value.value;
|
|
408
|
+
index = value.nextIndex;
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
if (current === "--limit" || current.startsWith("--limit=")) {
|
|
412
|
+
const value = parseFlagValue(parsed.args, index, "--limit");
|
|
413
|
+
const parsedLimit = Number.parseInt(value.value, 10);
|
|
414
|
+
if (!Number.isFinite(parsedLimit) || parsedLimit <= 0) {
|
|
415
|
+
throw new ScoutCliError(`invalid limit: ${value.value}`);
|
|
416
|
+
}
|
|
417
|
+
limit = parsedLimit;
|
|
418
|
+
index = value.nextIndex;
|
|
419
|
+
continue;
|
|
420
|
+
}
|
|
421
|
+
unexpectedArgs("latest", args);
|
|
422
|
+
}
|
|
423
|
+
return {
|
|
424
|
+
currentDirectory: parsed.currentDirectory,
|
|
425
|
+
args: parsed.args,
|
|
426
|
+
agentId,
|
|
427
|
+
actorId,
|
|
428
|
+
conversationId,
|
|
429
|
+
limit
|
|
430
|
+
};
|
|
431
|
+
}
|
|
385
432
|
function parseEnrollCommandOptions(args, defaultCurrentDirectory) {
|
|
386
433
|
const parsed = parseContextRootPrefix(args, defaultCurrentDirectory);
|
|
387
434
|
let agentName = null;
|
|
@@ -2635,31 +2682,6 @@ var init_user_project_hints = __esm(() => {
|
|
|
2635
2682
|
});
|
|
2636
2683
|
|
|
2637
2684
|
// ../runtime/src/setup.ts
|
|
2638
|
-
var exports_setup = {};
|
|
2639
|
-
__export(exports_setup, {
|
|
2640
|
-
writeRelayAgentOverrides: () => writeRelayAgentOverrides,
|
|
2641
|
-
writeProjectConfig: () => writeProjectConfig,
|
|
2642
|
-
writeOpenScoutSettings: () => writeOpenScoutSettings,
|
|
2643
|
-
resolveRelayAgentConfig: () => resolveRelayAgentConfig,
|
|
2644
|
-
readRelayAgentOverrides: () => readRelayAgentOverrides,
|
|
2645
|
-
readProjectConfig: () => readProjectConfig,
|
|
2646
|
-
readOpenScoutSettings: () => readOpenScoutSettings,
|
|
2647
|
-
primaryDirectConversationIdForAgent: () => primaryDirectConversationIdForAgent,
|
|
2648
|
-
loadResolvedRelayAgents: () => loadResolvedRelayAgents,
|
|
2649
|
-
installScoutSkillToHarnesses: () => installScoutSkillToHarnesses,
|
|
2650
|
-
initializeOpenScoutSetup: () => initializeOpenScoutSetup,
|
|
2651
|
-
findNearestProjectRoot: () => findNearestProjectRoot,
|
|
2652
|
-
ensureScoutRelayAgentConfigured: () => ensureScoutRelayAgentConfigured,
|
|
2653
|
-
ensureRelayAgentConfigured: () => ensureRelayAgentConfigured,
|
|
2654
|
-
ensureProjectConfigForDirectory: () => ensureProjectConfigForDirectory,
|
|
2655
|
-
detectPreferredHarness: () => detectPreferredHarness,
|
|
2656
|
-
clearGitBranchCache: () => clearGitBranchCache,
|
|
2657
|
-
buildRelayAgentInstance: () => buildRelayAgentInstance,
|
|
2658
|
-
SCOUT_PRIMARY_CONVERSATION_ID: () => SCOUT_PRIMARY_CONVERSATION_ID,
|
|
2659
|
-
SCOUT_AGENT_ID: () => SCOUT_AGENT_ID,
|
|
2660
|
-
MANAGED_AGENT_HARNESSES: () => MANAGED_AGENT_HARNESSES,
|
|
2661
|
-
DEFAULT_OPERATOR_NAME: () => DEFAULT_OPERATOR_NAME
|
|
2662
|
-
});
|
|
2663
2685
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
2664
2686
|
import { existsSync as existsSync3, readFileSync } from "fs";
|
|
2665
2687
|
import { access, mkdir as mkdir2, readdir as readdir2, readFile as readFile3, realpath, rm, stat as stat2, writeFile as writeFile2 } from "fs/promises";
|
|
@@ -2838,13 +2860,6 @@ function normalizeTelegramConversationId(value) {
|
|
|
2838
2860
|
}
|
|
2839
2861
|
return normalized;
|
|
2840
2862
|
}
|
|
2841
|
-
function primaryDirectConversationIdForAgent(agentId) {
|
|
2842
|
-
const normalizedAgentId = normalizeAgentId(agentId);
|
|
2843
|
-
if (normalizedAgentId === SCOUT_AGENT_ID) {
|
|
2844
|
-
return SCOUT_PRIMARY_CONVERSATION_ID;
|
|
2845
|
-
}
|
|
2846
|
-
return `dm.operator.${normalizedAgentId}`;
|
|
2847
|
-
}
|
|
2848
2863
|
function resolveNodeQualifier() {
|
|
2849
2864
|
const fromEnv = process.env.OPENSCOUT_NODE_QUALIFIER?.trim();
|
|
2850
2865
|
if (fromEnv) {
|
|
@@ -2890,13 +2905,6 @@ function detectGitBranch(projectRoot) {
|
|
|
2890
2905
|
gitBranchCache.set(projectRoot, { branch, expiresAt: now + GIT_BRANCH_CACHE_TTL_MS });
|
|
2891
2906
|
return branch;
|
|
2892
2907
|
}
|
|
2893
|
-
function clearGitBranchCache(projectRoot) {
|
|
2894
|
-
if (projectRoot) {
|
|
2895
|
-
gitBranchCache.delete(projectRoot);
|
|
2896
|
-
} else {
|
|
2897
|
-
gitBranchCache.clear();
|
|
2898
|
-
}
|
|
2899
|
-
}
|
|
2900
2908
|
function resolveWorkspaceQualifier(projectRoot) {
|
|
2901
2909
|
const normalizedProjectRoot = normalizePath(projectRoot);
|
|
2902
2910
|
const branch = detectGitBranch(normalizedProjectRoot);
|
|
@@ -4383,52 +4391,6 @@ async function ensureRelayAgentConfigured(value, options = {}) {
|
|
|
4383
4391
|
registrationKind: "configured"
|
|
4384
4392
|
};
|
|
4385
4393
|
}
|
|
4386
|
-
async function ensureScoutRelayAgentConfigured(options = {}) {
|
|
4387
|
-
const settings = await readOpenScoutSettings({ currentDirectory: options.currentDirectory });
|
|
4388
|
-
const overrides = await readRelayAgentOverrides();
|
|
4389
|
-
const resolvedProjectRoot = options.projectRoot ? normalizePath(options.projectRoot) : options.currentDirectory ? await findNearestProjectRoot(options.currentDirectory) ?? normalizePath(options.currentDirectory) : normalizePath(process.cwd());
|
|
4390
|
-
const qualifiedAgentId = buildRelayAgentInstance(SCOUT_AGENT_ID, resolvedProjectRoot).id;
|
|
4391
|
-
const existing = overrides[qualifiedAgentId] ?? overrides[SCOUT_AGENT_ID];
|
|
4392
|
-
const nextOverride = {
|
|
4393
|
-
...existing,
|
|
4394
|
-
agentId: qualifiedAgentId,
|
|
4395
|
-
definitionId: SCOUT_AGENT_ID,
|
|
4396
|
-
displayName: "Scout",
|
|
4397
|
-
projectName: "OpenScout",
|
|
4398
|
-
projectRoot: resolvedProjectRoot,
|
|
4399
|
-
projectConfigPath: existing?.projectConfigPath ? normalizePath(existing.projectConfigPath) : null,
|
|
4400
|
-
source: "manual",
|
|
4401
|
-
startedAt: existing?.startedAt ?? nowSeconds(),
|
|
4402
|
-
systemPrompt: existing?.systemPrompt?.trim() || undefined,
|
|
4403
|
-
capabilities: normalizeCapabilities(existing?.capabilities),
|
|
4404
|
-
defaultHarness: "claude",
|
|
4405
|
-
harnessProfiles: buildHarnessProfiles({
|
|
4406
|
-
projectRoot: resolvedProjectRoot,
|
|
4407
|
-
sessionKey: qualifiedAgentId,
|
|
4408
|
-
sessionPrefix: settings.agents.sessionPrefix,
|
|
4409
|
-
defaultHarness: "claude",
|
|
4410
|
-
profiles: existing?.harnessProfiles,
|
|
4411
|
-
runtime: existing?.runtime,
|
|
4412
|
-
launchArgs: normalizeLaunchArgs(existing?.launchArgs)
|
|
4413
|
-
}),
|
|
4414
|
-
runtime: {
|
|
4415
|
-
cwd: resolvedProjectRoot,
|
|
4416
|
-
harness: "claude",
|
|
4417
|
-
transport: "claude_stream_json",
|
|
4418
|
-
sessionId: normalizeTmuxSessionName(existing?.runtime?.sessionId, `${SCOUT_AGENT_ID}-claude`, settings.agents.sessionPrefix),
|
|
4419
|
-
wakePolicy: "on_demand"
|
|
4420
|
-
}
|
|
4421
|
-
};
|
|
4422
|
-
nextOverride.launchArgs = nextOverride.harnessProfiles?.claude?.launchArgs ?? [];
|
|
4423
|
-
if (overrides[SCOUT_AGENT_ID]) {
|
|
4424
|
-
delete overrides[SCOUT_AGENT_ID];
|
|
4425
|
-
}
|
|
4426
|
-
if (JSON.stringify(overrides[qualifiedAgentId]) !== JSON.stringify(nextOverride)) {
|
|
4427
|
-
overrides[qualifiedAgentId] = nextOverride;
|
|
4428
|
-
await writeRelayAgentOverrides(overrides);
|
|
4429
|
-
}
|
|
4430
|
-
return nextOverride;
|
|
4431
|
-
}
|
|
4432
4394
|
async function initializeOpenScoutSetup(options = {}) {
|
|
4433
4395
|
return loadResolvedRelayAgents({
|
|
4434
4396
|
currentDirectory: options.currentDirectory,
|
|
@@ -4592,418 +4554,6 @@ async function readOptionalFile(filePath) {
|
|
|
4592
4554
|
return null;
|
|
4593
4555
|
}
|
|
4594
4556
|
}
|
|
4595
|
-
function parseJsonObject(value) {
|
|
4596
|
-
const trimmed = value?.trim();
|
|
4597
|
-
if (!trimmed) {
|
|
4598
|
-
return {};
|
|
4599
|
-
}
|
|
4600
|
-
try {
|
|
4601
|
-
const parsed = JSON.parse(trimmed);
|
|
4602
|
-
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
4603
|
-
} catch {
|
|
4604
|
-
return {};
|
|
4605
|
-
}
|
|
4606
|
-
}
|
|
4607
|
-
function appendActionOutput(blockState, output) {
|
|
4608
|
-
if (!blockState || blockState.block.type !== "action" || !output) {
|
|
4609
|
-
return;
|
|
4610
|
-
}
|
|
4611
|
-
const actionBlock = blockState.block;
|
|
4612
|
-
actionBlock.action.output += output;
|
|
4613
|
-
}
|
|
4614
|
-
function updateBlockCompletion(blockState, completed) {
|
|
4615
|
-
if (!blockState) {
|
|
4616
|
-
return;
|
|
4617
|
-
}
|
|
4618
|
-
blockState.status = completed ? "completed" : "streaming";
|
|
4619
|
-
blockState.block.status = completed ? "completed" : "streaming";
|
|
4620
|
-
}
|
|
4621
|
-
function parseQuestionAnswer(value) {
|
|
4622
|
-
if (Array.isArray(value)) {
|
|
4623
|
-
return value.map((entry) => typeof entry === "string" ? entry.trim() : String(entry).trim()).filter(Boolean);
|
|
4624
|
-
}
|
|
4625
|
-
if (typeof value === "string") {
|
|
4626
|
-
return value.split(",").map((entry) => entry.trim()).filter(Boolean);
|
|
4627
|
-
}
|
|
4628
|
-
if (value == null) {
|
|
4629
|
-
return [];
|
|
4630
|
-
}
|
|
4631
|
-
return [String(value)];
|
|
4632
|
-
}
|
|
4633
|
-
function isClaudeSessionGlobalEvent(event) {
|
|
4634
|
-
return event.type === "system" && event.subtype === "init";
|
|
4635
|
-
}
|
|
4636
|
-
function stringifyToolResultContent(value) {
|
|
4637
|
-
if (typeof value === "string") {
|
|
4638
|
-
return value;
|
|
4639
|
-
}
|
|
4640
|
-
if (Array.isArray(value)) {
|
|
4641
|
-
return value.map((entry) => stringifyToolResultContent(entry)).filter(Boolean).join(`
|
|
4642
|
-
`);
|
|
4643
|
-
}
|
|
4644
|
-
if (value == null) {
|
|
4645
|
-
return "";
|
|
4646
|
-
}
|
|
4647
|
-
try {
|
|
4648
|
-
return JSON.stringify(value);
|
|
4649
|
-
} catch {
|
|
4650
|
-
return String(value);
|
|
4651
|
-
}
|
|
4652
|
-
}
|
|
4653
|
-
function buildClaudeAction(toolName, toolUseId, input) {
|
|
4654
|
-
if (toolName === "Edit" || toolName === "Write" || toolName === "MultiEdit") {
|
|
4655
|
-
return {
|
|
4656
|
-
kind: "file_change",
|
|
4657
|
-
path: typeof input.file_path === "string" ? input.file_path : typeof input.path === "string" ? input.path : "",
|
|
4658
|
-
diff: "",
|
|
4659
|
-
status: "running",
|
|
4660
|
-
output: ""
|
|
4661
|
-
};
|
|
4662
|
-
}
|
|
4663
|
-
if (toolName === "Bash") {
|
|
4664
|
-
return {
|
|
4665
|
-
kind: "command",
|
|
4666
|
-
command: typeof input.command === "string" ? input.command : "",
|
|
4667
|
-
status: "running",
|
|
4668
|
-
output: ""
|
|
4669
|
-
};
|
|
4670
|
-
}
|
|
4671
|
-
if (toolName === "Agent") {
|
|
4672
|
-
return {
|
|
4673
|
-
kind: "subagent",
|
|
4674
|
-
agentId: toolUseId,
|
|
4675
|
-
agentName: typeof input.description === "string" ? input.description : undefined,
|
|
4676
|
-
prompt: typeof input.prompt === "string" ? input.prompt : undefined,
|
|
4677
|
-
status: "running",
|
|
4678
|
-
output: ""
|
|
4679
|
-
};
|
|
4680
|
-
}
|
|
4681
|
-
return {
|
|
4682
|
-
kind: "tool_call",
|
|
4683
|
-
toolName,
|
|
4684
|
-
toolCallId: toolUseId,
|
|
4685
|
-
input,
|
|
4686
|
-
status: "running",
|
|
4687
|
-
output: ""
|
|
4688
|
-
};
|
|
4689
|
-
}
|
|
4690
|
-
function buildClaudeStreamJsonSessionSnapshot(raw, options, targetClaudeSessionId) {
|
|
4691
|
-
const lines = raw.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
4692
|
-
let resolvedSessionId = targetClaudeSessionId?.trim() || null;
|
|
4693
|
-
if (!resolvedSessionId) {
|
|
4694
|
-
for (const line of lines) {
|
|
4695
|
-
try {
|
|
4696
|
-
const event = JSON.parse(line);
|
|
4697
|
-
const nextSessionId = typeof event.session_id === "string" ? event.session_id : typeof event.sessionId === "string" ? event.sessionId : null;
|
|
4698
|
-
if (event.type === "system" && event.subtype === "init" && nextSessionId) {
|
|
4699
|
-
resolvedSessionId = nextSessionId;
|
|
4700
|
-
} else if (!resolvedSessionId && nextSessionId) {
|
|
4701
|
-
resolvedSessionId = nextSessionId;
|
|
4702
|
-
}
|
|
4703
|
-
} catch {}
|
|
4704
|
-
}
|
|
4705
|
-
}
|
|
4706
|
-
const snapshot = {
|
|
4707
|
-
session: {
|
|
4708
|
-
id: options.sessionId,
|
|
4709
|
-
name: options.agentName,
|
|
4710
|
-
adapterType: "claude_stream_json",
|
|
4711
|
-
status: "idle",
|
|
4712
|
-
cwd: options.cwd,
|
|
4713
|
-
providerMeta: resolvedSessionId ? { transportSessionId: resolvedSessionId } : undefined
|
|
4714
|
-
},
|
|
4715
|
-
turns: []
|
|
4716
|
-
};
|
|
4717
|
-
let currentTurn = null;
|
|
4718
|
-
const blockById = new Map;
|
|
4719
|
-
let activeContentBlocks = new Map;
|
|
4720
|
-
let pendingToolBlocks = new Map;
|
|
4721
|
-
const startTurn = () => {
|
|
4722
|
-
const turn = {
|
|
4723
|
-
id: `${options.sessionId}:turn:${snapshot.turns.length + 1}`,
|
|
4724
|
-
status: "streaming",
|
|
4725
|
-
blocks: [],
|
|
4726
|
-
startedAt: Date.now(),
|
|
4727
|
-
nextBlockIndex: 0,
|
|
4728
|
-
nextMessageIndex: 0
|
|
4729
|
-
};
|
|
4730
|
-
snapshot.turns.push(turn);
|
|
4731
|
-
snapshot.currentTurnId = turn.id;
|
|
4732
|
-
currentTurn = turn;
|
|
4733
|
-
activeContentBlocks = new Map;
|
|
4734
|
-
pendingToolBlocks = new Map;
|
|
4735
|
-
snapshot.session.status = "active";
|
|
4736
|
-
return turn;
|
|
4737
|
-
};
|
|
4738
|
-
const ensureTurn = () => currentTurn ?? startTurn();
|
|
4739
|
-
const startTextualBlock = (type, index, initialText = "") => {
|
|
4740
|
-
const turn = ensureTurn();
|
|
4741
|
-
const blockId = `${turn.id}:m${turn.nextMessageIndex}:i${index}`;
|
|
4742
|
-
const block = type === "text" ? {
|
|
4743
|
-
id: blockId,
|
|
4744
|
-
turnId: turn.id,
|
|
4745
|
-
index: turn.nextBlockIndex++,
|
|
4746
|
-
type: "text",
|
|
4747
|
-
text: initialText,
|
|
4748
|
-
status: "streaming"
|
|
4749
|
-
} : {
|
|
4750
|
-
id: blockId,
|
|
4751
|
-
turnId: turn.id,
|
|
4752
|
-
index: turn.nextBlockIndex++,
|
|
4753
|
-
type: "reasoning",
|
|
4754
|
-
text: initialText,
|
|
4755
|
-
status: "streaming"
|
|
4756
|
-
};
|
|
4757
|
-
const blockState = {
|
|
4758
|
-
block,
|
|
4759
|
-
status: "streaming"
|
|
4760
|
-
};
|
|
4761
|
-
turn.blocks.push(blockState);
|
|
4762
|
-
blockById.set(blockId, blockState);
|
|
4763
|
-
activeContentBlocks.set(index, blockState);
|
|
4764
|
-
return blockState;
|
|
4765
|
-
};
|
|
4766
|
-
const finalizeCurrentTurn = (status) => {
|
|
4767
|
-
if (!currentTurn) {
|
|
4768
|
-
return;
|
|
4769
|
-
}
|
|
4770
|
-
for (const blockState of activeContentBlocks.values()) {
|
|
4771
|
-
updateBlockCompletion(blockState, true);
|
|
4772
|
-
}
|
|
4773
|
-
activeContentBlocks.clear();
|
|
4774
|
-
currentTurn.status = status;
|
|
4775
|
-
currentTurn.endedAt = Date.now();
|
|
4776
|
-
currentTurn = null;
|
|
4777
|
-
snapshot.currentTurnId = undefined;
|
|
4778
|
-
snapshot.session.status = status === "error" ? "error" : "idle";
|
|
4779
|
-
};
|
|
4780
|
-
for (const line of lines) {
|
|
4781
|
-
let event;
|
|
4782
|
-
try {
|
|
4783
|
-
event = JSON.parse(line);
|
|
4784
|
-
} catch {
|
|
4785
|
-
continue;
|
|
4786
|
-
}
|
|
4787
|
-
const eventSessionId = typeof event.session_id === "string" ? event.session_id : typeof event.sessionId === "string" ? event.sessionId : null;
|
|
4788
|
-
if (resolvedSessionId) {
|
|
4789
|
-
if (eventSessionId && eventSessionId !== resolvedSessionId) {
|
|
4790
|
-
continue;
|
|
4791
|
-
}
|
|
4792
|
-
if (!eventSessionId && !isClaudeSessionGlobalEvent(event)) {
|
|
4793
|
-
continue;
|
|
4794
|
-
}
|
|
4795
|
-
}
|
|
4796
|
-
if (event.type === "system" && event.subtype === "init") {
|
|
4797
|
-
if (typeof event.model === "string" && event.model.trim()) {
|
|
4798
|
-
snapshot.session.model = event.model;
|
|
4799
|
-
}
|
|
4800
|
-
if (typeof event.cwd === "string" && event.cwd.trim()) {
|
|
4801
|
-
snapshot.session.cwd = event.cwd;
|
|
4802
|
-
}
|
|
4803
|
-
snapshot.session.status = currentTurn ? "active" : "idle";
|
|
4804
|
-
continue;
|
|
4805
|
-
}
|
|
4806
|
-
if (event.type === "stream_event") {
|
|
4807
|
-
const streamEvent = event.event;
|
|
4808
|
-
const streamEventType = typeof streamEvent?.type === "string" ? streamEvent.type : "";
|
|
4809
|
-
if (streamEventType === "message_start") {
|
|
4810
|
-
const turn = ensureTurn();
|
|
4811
|
-
turn.nextMessageIndex += 1;
|
|
4812
|
-
activeContentBlocks.clear();
|
|
4813
|
-
pendingToolBlocks.clear();
|
|
4814
|
-
snapshot.session.status = "active";
|
|
4815
|
-
continue;
|
|
4816
|
-
}
|
|
4817
|
-
if (streamEventType === "content_block_start") {
|
|
4818
|
-
const turn = ensureTurn();
|
|
4819
|
-
const blockIndex = typeof streamEvent?.index === "number" ? streamEvent.index : 0;
|
|
4820
|
-
const contentBlock = streamEvent?.content_block;
|
|
4821
|
-
const contentType = typeof contentBlock?.type === "string" ? contentBlock.type : "";
|
|
4822
|
-
if (contentType === "thinking") {
|
|
4823
|
-
startTextualBlock("reasoning", blockIndex, typeof contentBlock?.thinking === "string" ? contentBlock.thinking : "");
|
|
4824
|
-
} else if (contentType === "text") {
|
|
4825
|
-
startTextualBlock("text", blockIndex, typeof contentBlock?.text === "string" ? contentBlock.text : "");
|
|
4826
|
-
} else if (contentType === "tool_use") {
|
|
4827
|
-
pendingToolBlocks.set(blockIndex, {
|
|
4828
|
-
toolUseId: typeof contentBlock?.id === "string" ? contentBlock.id : `${turn.id}:tool:${blockIndex}`,
|
|
4829
|
-
toolName: typeof contentBlock?.name === "string" ? contentBlock.name : "unknown",
|
|
4830
|
-
input: contentBlock?.input && typeof contentBlock.input === "object" && !Array.isArray(contentBlock.input) ? contentBlock.input : {},
|
|
4831
|
-
inputJson: "",
|
|
4832
|
-
blockIndex: turn.nextBlockIndex++
|
|
4833
|
-
});
|
|
4834
|
-
}
|
|
4835
|
-
continue;
|
|
4836
|
-
}
|
|
4837
|
-
if (streamEventType === "content_block_delta") {
|
|
4838
|
-
const blockIndex = typeof streamEvent?.index === "number" ? streamEvent.index : 0;
|
|
4839
|
-
const delta = streamEvent?.delta;
|
|
4840
|
-
const deltaType = typeof delta?.type === "string" ? delta.type : "";
|
|
4841
|
-
if (deltaType === "text_delta") {
|
|
4842
|
-
const blockState = activeContentBlocks.get(blockIndex);
|
|
4843
|
-
if (blockState?.block.type === "text" && typeof delta?.text === "string") {
|
|
4844
|
-
blockState.block.text += delta.text;
|
|
4845
|
-
}
|
|
4846
|
-
continue;
|
|
4847
|
-
}
|
|
4848
|
-
if (deltaType === "thinking_delta") {
|
|
4849
|
-
const blockState = activeContentBlocks.get(blockIndex);
|
|
4850
|
-
if (blockState?.block.type === "reasoning" && typeof delta?.thinking === "string") {
|
|
4851
|
-
blockState.block.text += delta.thinking;
|
|
4852
|
-
}
|
|
4853
|
-
continue;
|
|
4854
|
-
}
|
|
4855
|
-
if (deltaType === "input_json_delta") {
|
|
4856
|
-
const pending = pendingToolBlocks.get(blockIndex);
|
|
4857
|
-
if (pending && typeof delta?.partial_json === "string") {
|
|
4858
|
-
pending.inputJson += delta.partial_json;
|
|
4859
|
-
}
|
|
4860
|
-
}
|
|
4861
|
-
continue;
|
|
4862
|
-
}
|
|
4863
|
-
if (streamEventType === "content_block_stop") {
|
|
4864
|
-
const blockIndex = typeof streamEvent?.index === "number" ? streamEvent.index : 0;
|
|
4865
|
-
const blockState = activeContentBlocks.get(blockIndex);
|
|
4866
|
-
if (blockState) {
|
|
4867
|
-
updateBlockCompletion(blockState, true);
|
|
4868
|
-
activeContentBlocks.delete(blockIndex);
|
|
4869
|
-
continue;
|
|
4870
|
-
}
|
|
4871
|
-
const pendingTool = pendingToolBlocks.get(blockIndex);
|
|
4872
|
-
if (!pendingTool) {
|
|
4873
|
-
continue;
|
|
4874
|
-
}
|
|
4875
|
-
const turn = ensureTurn();
|
|
4876
|
-
const parsedInput = {
|
|
4877
|
-
...pendingTool.input,
|
|
4878
|
-
...parseJsonObject(pendingTool.inputJson)
|
|
4879
|
-
};
|
|
4880
|
-
if (pendingTool.toolName === "AskUserQuestion") {
|
|
4881
|
-
const questions = Array.isArray(parsedInput.questions) ? parsedInput.questions : [];
|
|
4882
|
-
const firstQuestion = questions[0] ?? {};
|
|
4883
|
-
const block = {
|
|
4884
|
-
id: pendingTool.toolUseId,
|
|
4885
|
-
turnId: turn.id,
|
|
4886
|
-
index: pendingTool.blockIndex,
|
|
4887
|
-
type: "question",
|
|
4888
|
-
header: typeof firstQuestion.header === "string" ? firstQuestion.header : undefined,
|
|
4889
|
-
question: typeof firstQuestion.question === "string" ? firstQuestion.question : "",
|
|
4890
|
-
options: Array.isArray(firstQuestion.options) ? firstQuestion.options.map((option) => {
|
|
4891
|
-
if (typeof option === "string") {
|
|
4892
|
-
return { label: option };
|
|
4893
|
-
}
|
|
4894
|
-
const optionRecord = option;
|
|
4895
|
-
return {
|
|
4896
|
-
label: typeof optionRecord.label === "string" ? optionRecord.label : String(option),
|
|
4897
|
-
description: typeof optionRecord.description === "string" ? optionRecord.description : undefined
|
|
4898
|
-
};
|
|
4899
|
-
}) : [],
|
|
4900
|
-
multiSelect: Boolean(firstQuestion.multiSelect),
|
|
4901
|
-
questionStatus: "awaiting_answer",
|
|
4902
|
-
status: "streaming"
|
|
4903
|
-
};
|
|
4904
|
-
const nextBlockState = { block, status: "streaming" };
|
|
4905
|
-
turn.blocks.push(nextBlockState);
|
|
4906
|
-
blockById.set(block.id, nextBlockState);
|
|
4907
|
-
} else {
|
|
4908
|
-
const block = {
|
|
4909
|
-
id: pendingTool.toolUseId,
|
|
4910
|
-
turnId: turn.id,
|
|
4911
|
-
index: pendingTool.blockIndex,
|
|
4912
|
-
type: "action",
|
|
4913
|
-
action: buildClaudeAction(pendingTool.toolName, pendingTool.toolUseId, parsedInput),
|
|
4914
|
-
status: "streaming"
|
|
4915
|
-
};
|
|
4916
|
-
const nextBlockState = { block, status: "streaming" };
|
|
4917
|
-
turn.blocks.push(nextBlockState);
|
|
4918
|
-
blockById.set(block.id, nextBlockState);
|
|
4919
|
-
}
|
|
4920
|
-
pendingToolBlocks.delete(blockIndex);
|
|
4921
|
-
}
|
|
4922
|
-
continue;
|
|
4923
|
-
}
|
|
4924
|
-
if (event.type === "user") {
|
|
4925
|
-
const message = event.message;
|
|
4926
|
-
const content = Array.isArray(message?.content) ? message.content : [];
|
|
4927
|
-
for (const entry of content) {
|
|
4928
|
-
const result = entry;
|
|
4929
|
-
if (result.type !== "tool_result" || typeof result.tool_use_id !== "string") {
|
|
4930
|
-
continue;
|
|
4931
|
-
}
|
|
4932
|
-
const blockState = blockById.get(result.tool_use_id);
|
|
4933
|
-
if (!blockState) {
|
|
4934
|
-
continue;
|
|
4935
|
-
}
|
|
4936
|
-
if (blockState.block.type === "question") {
|
|
4937
|
-
const questionBlock = blockState.block;
|
|
4938
|
-
questionBlock.questionStatus = result.is_error ? "denied" : "answered";
|
|
4939
|
-
const answer = parseQuestionAnswer(result.content);
|
|
4940
|
-
questionBlock.answer = answer.length > 0 ? answer : undefined;
|
|
4941
|
-
updateBlockCompletion(blockState, true);
|
|
4942
|
-
continue;
|
|
4943
|
-
}
|
|
4944
|
-
appendActionOutput(blockState, stringifyToolResultContent(result.content));
|
|
4945
|
-
if (blockState.block.type === "action") {
|
|
4946
|
-
blockState.block.action.status = result.is_error ? "failed" : "completed";
|
|
4947
|
-
}
|
|
4948
|
-
updateBlockCompletion(blockState, true);
|
|
4949
|
-
}
|
|
4950
|
-
continue;
|
|
4951
|
-
}
|
|
4952
|
-
if (event.type === "result") {
|
|
4953
|
-
const permissionDenials = Array.isArray(event.permission_denials) ? event.permission_denials : [];
|
|
4954
|
-
for (const denial of permissionDenials) {
|
|
4955
|
-
if (denial.tool_name !== "AskUserQuestion") {
|
|
4956
|
-
continue;
|
|
4957
|
-
}
|
|
4958
|
-
const toolUseId = typeof denial.tool_use_id === "string" ? denial.tool_use_id : null;
|
|
4959
|
-
const blockState = toolUseId ? blockById.get(toolUseId) : undefined;
|
|
4960
|
-
if (blockState?.block.type === "question") {
|
|
4961
|
-
blockState.block.questionStatus = "denied";
|
|
4962
|
-
updateBlockCompletion(blockState, true);
|
|
4963
|
-
continue;
|
|
4964
|
-
}
|
|
4965
|
-
const input = denial.tool_input && typeof denial.tool_input === "object" && !Array.isArray(denial.tool_input) ? denial.tool_input : {};
|
|
4966
|
-
const questions = Array.isArray(input.questions) ? input.questions : [];
|
|
4967
|
-
const firstQuestion = questions[0] ?? {};
|
|
4968
|
-
const turn = ensureTurn();
|
|
4969
|
-
const block = {
|
|
4970
|
-
id: toolUseId ?? `${turn.id}:denied:${turn.nextBlockIndex}`,
|
|
4971
|
-
turnId: turn.id,
|
|
4972
|
-
index: turn.nextBlockIndex++,
|
|
4973
|
-
type: "question",
|
|
4974
|
-
header: typeof firstQuestion.header === "string" ? firstQuestion.header : undefined,
|
|
4975
|
-
question: typeof firstQuestion.question === "string" ? firstQuestion.question : "",
|
|
4976
|
-
options: Array.isArray(firstQuestion.options) ? firstQuestion.options.map((option) => {
|
|
4977
|
-
if (typeof option === "string") {
|
|
4978
|
-
return { label: option };
|
|
4979
|
-
}
|
|
4980
|
-
const optionRecord = option;
|
|
4981
|
-
return {
|
|
4982
|
-
label: typeof optionRecord.label === "string" ? optionRecord.label : String(option),
|
|
4983
|
-
description: typeof optionRecord.description === "string" ? optionRecord.description : undefined
|
|
4984
|
-
};
|
|
4985
|
-
}) : [],
|
|
4986
|
-
multiSelect: Boolean(firstQuestion.multiSelect),
|
|
4987
|
-
questionStatus: "denied",
|
|
4988
|
-
status: "completed"
|
|
4989
|
-
};
|
|
4990
|
-
const deniedBlock = { block, status: "completed" };
|
|
4991
|
-
turn.blocks.push(deniedBlock);
|
|
4992
|
-
blockById.set(block.id, deniedBlock);
|
|
4993
|
-
}
|
|
4994
|
-
finalizeCurrentTurn(event.is_error ? "error" : "completed");
|
|
4995
|
-
continue;
|
|
4996
|
-
}
|
|
4997
|
-
if (event.type === "error") {
|
|
4998
|
-
finalizeCurrentTurn("error");
|
|
4999
|
-
}
|
|
5000
|
-
}
|
|
5001
|
-
if (!resolvedSessionId && snapshot.turns.length === 0) {
|
|
5002
|
-
return null;
|
|
5003
|
-
}
|
|
5004
|
-
snapshot.session.status = currentTurn ? "active" : snapshot.session.status;
|
|
5005
|
-
return snapshot;
|
|
5006
|
-
}
|
|
5007
4557
|
|
|
5008
4558
|
class ClaudeStreamJsonSession {
|
|
5009
4559
|
options;
|
|
@@ -5286,35 +4836,10 @@ async function ensureClaudeStreamJsonAgentOnline(options) {
|
|
|
5286
4836
|
session.update(options);
|
|
5287
4837
|
return session.ensureOnline();
|
|
5288
4838
|
}
|
|
5289
|
-
async function invokeClaudeStreamJsonAgent(options) {
|
|
5290
|
-
const session = getOrCreateSession(options);
|
|
5291
|
-
session.update(options);
|
|
5292
|
-
return session.invoke(options.prompt, options.timeoutMs);
|
|
5293
|
-
}
|
|
5294
4839
|
function isClaudeStreamJsonAgentAlive(options) {
|
|
5295
4840
|
const session = sessions.get(sessionKey(options));
|
|
5296
4841
|
return Boolean(session?.isAlive());
|
|
5297
4842
|
}
|
|
5298
|
-
async function answerClaudeStreamJsonQuestion(options, input) {
|
|
5299
|
-
const session = sessions.get(sessionKey(options));
|
|
5300
|
-
if (!session) {
|
|
5301
|
-
throw new Error(`Claude stream-json session for ${options.agentName} is not running.`);
|
|
5302
|
-
}
|
|
5303
|
-
session.update(options);
|
|
5304
|
-
await session.answerQuestion(input.blockId, input.answer);
|
|
5305
|
-
}
|
|
5306
|
-
async function getClaudeStreamJsonAgentSnapshot(options) {
|
|
5307
|
-
const stdoutLogPath = join5(options.logsDirectory, "stdout.log");
|
|
5308
|
-
const sessionStatePath = join5(options.runtimeDirectory, "claude-session-id.txt");
|
|
5309
|
-
const [rawLog, persistedSessionId] = await Promise.all([
|
|
5310
|
-
readOptionalFile(stdoutLogPath),
|
|
5311
|
-
readOptionalFile(sessionStatePath)
|
|
5312
|
-
]);
|
|
5313
|
-
if (!rawLog) {
|
|
5314
|
-
return null;
|
|
5315
|
-
}
|
|
5316
|
-
return buildClaudeStreamJsonSessionSnapshot(rawLog, options, persistedSessionId);
|
|
5317
|
-
}
|
|
5318
4843
|
async function shutdownClaudeStreamJsonAgent(options, shutdownOptions = {}) {
|
|
5319
4844
|
const key = sessionKey(options);
|
|
5320
4845
|
const session = sessions.get(key);
|
|
@@ -5336,11 +4861,6 @@ var init_claude_stream_json = __esm(() => {
|
|
|
5336
4861
|
import { spawn as spawn2 } from "child_process";
|
|
5337
4862
|
import { access as access2, appendFile as appendFile2, constants, mkdir as mkdir4, readFile as readFile5, rm as rm3, writeFile as writeFile4 } from "fs/promises";
|
|
5338
4863
|
import { delimiter, join as join6 } from "path";
|
|
5339
|
-
function isCodexThreadGlobalMessage(message) {
|
|
5340
|
-
const result = message.result;
|
|
5341
|
-
const thread = result?.thread;
|
|
5342
|
-
return typeof thread?.id === "string";
|
|
5343
|
-
}
|
|
5344
4864
|
function sessionKey2(options) {
|
|
5345
4865
|
return `${options.agentName}:${options.sessionId}`;
|
|
5346
4866
|
}
|
|
@@ -5407,14 +4927,6 @@ function parseJsonLine(line) {
|
|
|
5407
4927
|
return null;
|
|
5408
4928
|
}
|
|
5409
4929
|
}
|
|
5410
|
-
function parseJsonRecord(line) {
|
|
5411
|
-
try {
|
|
5412
|
-
const value = JSON.parse(line);
|
|
5413
|
-
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
5414
|
-
} catch {
|
|
5415
|
-
return null;
|
|
5416
|
-
}
|
|
5417
|
-
}
|
|
5418
4930
|
function errorMessage2(error) {
|
|
5419
4931
|
if (error instanceof Error) {
|
|
5420
4932
|
return error.message;
|
|
@@ -5453,687 +4965,6 @@ async function readOptionalFile2(filePath) {
|
|
|
5453
4965
|
return null;
|
|
5454
4966
|
}
|
|
5455
4967
|
}
|
|
5456
|
-
async function readOptionalJsonRecord(filePath) {
|
|
5457
|
-
const raw = await readOptionalFile2(filePath);
|
|
5458
|
-
return raw ? parseJsonRecord(raw) : null;
|
|
5459
|
-
}
|
|
5460
|
-
function codexThreadStatusToSessionStatus(status) {
|
|
5461
|
-
switch (status) {
|
|
5462
|
-
case "active":
|
|
5463
|
-
return "active";
|
|
5464
|
-
case "idle":
|
|
5465
|
-
return "idle";
|
|
5466
|
-
case "error":
|
|
5467
|
-
return "error";
|
|
5468
|
-
default:
|
|
5469
|
-
return "connecting";
|
|
5470
|
-
}
|
|
5471
|
-
}
|
|
5472
|
-
function codexTurnStatusToTurnStatus(status) {
|
|
5473
|
-
switch (status) {
|
|
5474
|
-
case "completed":
|
|
5475
|
-
return "completed";
|
|
5476
|
-
case "interrupted":
|
|
5477
|
-
return "interrupted";
|
|
5478
|
-
case "failed":
|
|
5479
|
-
return "error";
|
|
5480
|
-
default:
|
|
5481
|
-
return "streaming";
|
|
5482
|
-
}
|
|
5483
|
-
}
|
|
5484
|
-
function stringifyCodexItem(value) {
|
|
5485
|
-
if (typeof value === "string") {
|
|
5486
|
-
return value;
|
|
5487
|
-
}
|
|
5488
|
-
if (value == null) {
|
|
5489
|
-
return "";
|
|
5490
|
-
}
|
|
5491
|
-
try {
|
|
5492
|
-
return JSON.stringify(value);
|
|
5493
|
-
} catch {
|
|
5494
|
-
return String(value);
|
|
5495
|
-
}
|
|
5496
|
-
}
|
|
5497
|
-
function parseCodexTimestamp(value) {
|
|
5498
|
-
if (typeof value === "number" && Number.isFinite(value)) {
|
|
5499
|
-
return value > 1000000000000 ? value : value * 1000;
|
|
5500
|
-
}
|
|
5501
|
-
if (typeof value === "string") {
|
|
5502
|
-
const parsed = Date.parse(value);
|
|
5503
|
-
if (Number.isFinite(parsed)) {
|
|
5504
|
-
return parsed;
|
|
5505
|
-
}
|
|
5506
|
-
}
|
|
5507
|
-
return;
|
|
5508
|
-
}
|
|
5509
|
-
function parseCodexMaybeJson(value) {
|
|
5510
|
-
if (typeof value !== "string") {
|
|
5511
|
-
return value;
|
|
5512
|
-
}
|
|
5513
|
-
const trimmed = value.trim();
|
|
5514
|
-
if (!trimmed) {
|
|
5515
|
-
return value;
|
|
5516
|
-
}
|
|
5517
|
-
try {
|
|
5518
|
-
return JSON.parse(trimmed);
|
|
5519
|
-
} catch {
|
|
5520
|
-
return value;
|
|
5521
|
-
}
|
|
5522
|
-
}
|
|
5523
|
-
function extractCodexReasoningText(item) {
|
|
5524
|
-
const summary = Array.isArray(item.summary) ? item.summary : [];
|
|
5525
|
-
const content = Array.isArray(item.content) ? item.content : [];
|
|
5526
|
-
const summaryText = summary.map((entry) => {
|
|
5527
|
-
if (typeof entry === "string") {
|
|
5528
|
-
return entry;
|
|
5529
|
-
}
|
|
5530
|
-
const record = entry;
|
|
5531
|
-
if (typeof record.text === "string") {
|
|
5532
|
-
return record.text;
|
|
5533
|
-
}
|
|
5534
|
-
if (typeof record.summary === "string") {
|
|
5535
|
-
return record.summary;
|
|
5536
|
-
}
|
|
5537
|
-
return "";
|
|
5538
|
-
}).filter(Boolean).join(`
|
|
5539
|
-
`);
|
|
5540
|
-
const contentText = content.map((entry) => {
|
|
5541
|
-
if (typeof entry === "string") {
|
|
5542
|
-
return entry;
|
|
5543
|
-
}
|
|
5544
|
-
const record = entry;
|
|
5545
|
-
return typeof record.text === "string" ? record.text : "";
|
|
5546
|
-
}).filter(Boolean).join(`
|
|
5547
|
-
`);
|
|
5548
|
-
return [summaryText, contentText].filter(Boolean).join(`
|
|
5549
|
-
|
|
5550
|
-
`).trim();
|
|
5551
|
-
}
|
|
5552
|
-
function extractCodexMessageText(item) {
|
|
5553
|
-
const content = Array.isArray(item.content) ? item.content : [];
|
|
5554
|
-
return content.map((entry) => {
|
|
5555
|
-
if (typeof entry === "string") {
|
|
5556
|
-
return entry;
|
|
5557
|
-
}
|
|
5558
|
-
const record = entry;
|
|
5559
|
-
return typeof record.text === "string" ? record.text : "";
|
|
5560
|
-
}).filter(Boolean).join(`
|
|
5561
|
-
|
|
5562
|
-
`).trim();
|
|
5563
|
-
}
|
|
5564
|
-
function extractCodexUserMessageText(item) {
|
|
5565
|
-
const text = extractCodexMessageText(item);
|
|
5566
|
-
if (text) {
|
|
5567
|
-
return text;
|
|
5568
|
-
}
|
|
5569
|
-
return typeof item.text === "string" ? item.text.trim() : "";
|
|
5570
|
-
}
|
|
5571
|
-
function renderCodexActionOutput(item) {
|
|
5572
|
-
if (typeof item.text === "string" && item.text.trim()) {
|
|
5573
|
-
return item.text;
|
|
5574
|
-
}
|
|
5575
|
-
if (item.action !== undefined) {
|
|
5576
|
-
return stringifyCodexItem(item.action);
|
|
5577
|
-
}
|
|
5578
|
-
return stringifyCodexItem(item);
|
|
5579
|
-
}
|
|
5580
|
-
function buildCodexActionBlock(item, turnId, index) {
|
|
5581
|
-
return {
|
|
5582
|
-
id: typeof item.id === "string" ? item.id : `${turnId}:action:${index}`,
|
|
5583
|
-
turnId,
|
|
5584
|
-
index,
|
|
5585
|
-
type: "action",
|
|
5586
|
-
status: "streaming",
|
|
5587
|
-
action: {
|
|
5588
|
-
kind: "tool_call",
|
|
5589
|
-
toolName: typeof item.type === "string" ? item.type : "unknown",
|
|
5590
|
-
toolCallId: typeof item.id === "string" ? item.id : `${turnId}:action:${index}`,
|
|
5591
|
-
input: item,
|
|
5592
|
-
output: "",
|
|
5593
|
-
status: "running"
|
|
5594
|
-
}
|
|
5595
|
-
};
|
|
5596
|
-
}
|
|
5597
|
-
function buildCodexRolloutActionBlock(item, turnId, index) {
|
|
5598
|
-
const itemType = typeof item.type === "string" ? item.type : "tool_call";
|
|
5599
|
-
const toolCallId = typeof item.call_id === "string" ? item.call_id : `${turnId}:action:${index}`;
|
|
5600
|
-
const toolName = typeof item.name === "string" ? item.name : itemType === "web_search_call" ? "web_search" : itemType;
|
|
5601
|
-
const input = itemType === "function_call" ? parseCodexMaybeJson(item.arguments) : itemType === "custom_tool_call" ? item.input : item;
|
|
5602
|
-
return {
|
|
5603
|
-
id: toolCallId,
|
|
5604
|
-
turnId,
|
|
5605
|
-
index,
|
|
5606
|
-
type: "action",
|
|
5607
|
-
status: "streaming",
|
|
5608
|
-
action: {
|
|
5609
|
-
kind: "tool_call",
|
|
5610
|
-
toolName,
|
|
5611
|
-
toolCallId,
|
|
5612
|
-
input,
|
|
5613
|
-
output: "",
|
|
5614
|
-
status: "running"
|
|
5615
|
-
}
|
|
5616
|
-
};
|
|
5617
|
-
}
|
|
5618
|
-
function finalizeCodexTurnBlocks(turn, status) {
|
|
5619
|
-
for (const blockState of turn.blocks) {
|
|
5620
|
-
if (blockState.status === "completed") {
|
|
5621
|
-
continue;
|
|
5622
|
-
}
|
|
5623
|
-
blockState.status = "completed";
|
|
5624
|
-
blockState.block.status = "completed";
|
|
5625
|
-
if (blockState.block.type === "action") {
|
|
5626
|
-
blockState.block.action.status = status === "completed" ? "completed" : "failed";
|
|
5627
|
-
}
|
|
5628
|
-
}
|
|
5629
|
-
}
|
|
5630
|
-
function setCodexProviderMeta(snapshot, threadId, threadPath) {
|
|
5631
|
-
if (!threadId && !threadPath) {
|
|
5632
|
-
return;
|
|
5633
|
-
}
|
|
5634
|
-
snapshot.session.providerMeta = {
|
|
5635
|
-
...snapshot.session.providerMeta ?? {},
|
|
5636
|
-
...threadId ? { threadId } : {},
|
|
5637
|
-
...threadPath ? { threadPath } : {}
|
|
5638
|
-
};
|
|
5639
|
-
}
|
|
5640
|
-
function buildCodexAppServerSessionSnapshot(raw, options, targetThreadId) {
|
|
5641
|
-
const lines = raw.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
5642
|
-
let resolvedThreadId = targetThreadId?.trim() || null;
|
|
5643
|
-
if (!resolvedThreadId) {
|
|
5644
|
-
for (const line of lines) {
|
|
5645
|
-
try {
|
|
5646
|
-
const message = JSON.parse(line);
|
|
5647
|
-
const resultThread = message.result?.thread;
|
|
5648
|
-
const paramsThread = message.params?.thread;
|
|
5649
|
-
const params = message.params;
|
|
5650
|
-
const nextThreadId = typeof resultThread?.id === "string" ? resultThread.id : typeof paramsThread?.id === "string" ? paramsThread.id : typeof params?.threadId === "string" ? params.threadId : null;
|
|
5651
|
-
if (nextThreadId) {
|
|
5652
|
-
resolvedThreadId = nextThreadId;
|
|
5653
|
-
}
|
|
5654
|
-
} catch {}
|
|
5655
|
-
}
|
|
5656
|
-
}
|
|
5657
|
-
const snapshot = {
|
|
5658
|
-
session: {
|
|
5659
|
-
id: options.sessionId,
|
|
5660
|
-
name: options.agentName,
|
|
5661
|
-
adapterType: "codex_app_server",
|
|
5662
|
-
status: resolvedThreadId ? "idle" : "connecting",
|
|
5663
|
-
cwd: options.cwd,
|
|
5664
|
-
providerMeta: resolvedThreadId ? { threadId: resolvedThreadId } : undefined
|
|
5665
|
-
},
|
|
5666
|
-
turns: []
|
|
5667
|
-
};
|
|
5668
|
-
const turnsById = new Map;
|
|
5669
|
-
const blocksById = new Map;
|
|
5670
|
-
const ensureTurn = (turnId) => {
|
|
5671
|
-
const existing = turnsById.get(turnId);
|
|
5672
|
-
if (existing) {
|
|
5673
|
-
return existing;
|
|
5674
|
-
}
|
|
5675
|
-
const turn = {
|
|
5676
|
-
id: turnId,
|
|
5677
|
-
status: "streaming",
|
|
5678
|
-
blocks: [],
|
|
5679
|
-
startedAt: Date.now(),
|
|
5680
|
-
nextBlockIndex: 0
|
|
5681
|
-
};
|
|
5682
|
-
turnsById.set(turnId, turn);
|
|
5683
|
-
snapshot.turns.push(turn);
|
|
5684
|
-
snapshot.currentTurnId = turnId;
|
|
5685
|
-
snapshot.session.status = "active";
|
|
5686
|
-
return turn;
|
|
5687
|
-
};
|
|
5688
|
-
const completeBlock = (blockState) => {
|
|
5689
|
-
if (!blockState) {
|
|
5690
|
-
return;
|
|
5691
|
-
}
|
|
5692
|
-
blockState.status = "completed";
|
|
5693
|
-
blockState.block.status = "completed";
|
|
5694
|
-
};
|
|
5695
|
-
for (const line of lines) {
|
|
5696
|
-
let message;
|
|
5697
|
-
try {
|
|
5698
|
-
message = JSON.parse(line);
|
|
5699
|
-
} catch {
|
|
5700
|
-
continue;
|
|
5701
|
-
}
|
|
5702
|
-
const params = message.params;
|
|
5703
|
-
const result = message.result;
|
|
5704
|
-
const paramsThread = params?.thread;
|
|
5705
|
-
const resultThread = result?.thread;
|
|
5706
|
-
const lineThreadId = typeof params?.threadId === "string" ? params.threadId : typeof paramsThread?.id === "string" ? paramsThread.id : typeof resultThread?.id === "string" ? resultThread.id : null;
|
|
5707
|
-
if (resolvedThreadId) {
|
|
5708
|
-
if (lineThreadId && lineThreadId !== resolvedThreadId) {
|
|
5709
|
-
continue;
|
|
5710
|
-
}
|
|
5711
|
-
if (!lineThreadId && !isCodexThreadGlobalMessage(message)) {
|
|
5712
|
-
continue;
|
|
5713
|
-
}
|
|
5714
|
-
}
|
|
5715
|
-
const resultModel = typeof result?.model === "string" ? result.model : null;
|
|
5716
|
-
if (resultThread && resultModel) {
|
|
5717
|
-
snapshot.session.model = resultModel;
|
|
5718
|
-
}
|
|
5719
|
-
if (typeof resultThread?.path === "string") {
|
|
5720
|
-
snapshot.session.providerMeta = {
|
|
5721
|
-
...snapshot.session.providerMeta ?? {},
|
|
5722
|
-
threadId: resolvedThreadId ?? resultThread.id,
|
|
5723
|
-
threadPath: resultThread.path
|
|
5724
|
-
};
|
|
5725
|
-
}
|
|
5726
|
-
if (typeof resultThread?.cwd === "string") {
|
|
5727
|
-
snapshot.session.cwd = resultThread.cwd;
|
|
5728
|
-
}
|
|
5729
|
-
if (message.method === "thread/started" || message.method === "thread/name/updated") {
|
|
5730
|
-
if (typeof paramsThread?.path === "string") {
|
|
5731
|
-
snapshot.session.providerMeta = {
|
|
5732
|
-
...snapshot.session.providerMeta ?? {},
|
|
5733
|
-
threadId: resolvedThreadId ?? paramsThread.id,
|
|
5734
|
-
threadPath: paramsThread.path
|
|
5735
|
-
};
|
|
5736
|
-
}
|
|
5737
|
-
if (typeof paramsThread?.cwd === "string") {
|
|
5738
|
-
snapshot.session.cwd = paramsThread.cwd;
|
|
5739
|
-
}
|
|
5740
|
-
if (typeof paramsThread?.name === "string" && paramsThread.name.trim()) {
|
|
5741
|
-
snapshot.session.name = paramsThread.name;
|
|
5742
|
-
}
|
|
5743
|
-
continue;
|
|
5744
|
-
}
|
|
5745
|
-
if (message.method === "thread/status/changed") {
|
|
5746
|
-
const status = params?.status?.type;
|
|
5747
|
-
snapshot.session.status = codexThreadStatusToSessionStatus(typeof status === "string" ? status : undefined);
|
|
5748
|
-
continue;
|
|
5749
|
-
}
|
|
5750
|
-
if (message.method === "turn/started") {
|
|
5751
|
-
const turn = params?.turn;
|
|
5752
|
-
if (typeof turn?.id === "string") {
|
|
5753
|
-
ensureTurn(turn.id);
|
|
5754
|
-
}
|
|
5755
|
-
continue;
|
|
5756
|
-
}
|
|
5757
|
-
if (message.method === "item/started") {
|
|
5758
|
-
const item = params?.item;
|
|
5759
|
-
const turnId = typeof params?.turnId === "string" ? params.turnId : null;
|
|
5760
|
-
const itemType = typeof item?.type === "string" ? item.type : "";
|
|
5761
|
-
const itemId = typeof item?.id === "string" ? item.id : null;
|
|
5762
|
-
if (!turnId || !item || !itemId || !itemType) {
|
|
5763
|
-
continue;
|
|
5764
|
-
}
|
|
5765
|
-
const turn = ensureTurn(turnId);
|
|
5766
|
-
if (itemType === "userMessage") {
|
|
5767
|
-
const block2 = {
|
|
5768
|
-
id: itemId,
|
|
5769
|
-
turnId,
|
|
5770
|
-
index: turn.nextBlockIndex++,
|
|
5771
|
-
type: "text",
|
|
5772
|
-
text: extractCodexUserMessageText(item),
|
|
5773
|
-
status: "streaming"
|
|
5774
|
-
};
|
|
5775
|
-
const blockState2 = { block: block2, status: "streaming" };
|
|
5776
|
-
turn.blocks.push(blockState2);
|
|
5777
|
-
blocksById.set(itemId, blockState2);
|
|
5778
|
-
continue;
|
|
5779
|
-
}
|
|
5780
|
-
if (itemType === "agentMessage") {
|
|
5781
|
-
const block2 = {
|
|
5782
|
-
id: itemId,
|
|
5783
|
-
turnId,
|
|
5784
|
-
index: turn.nextBlockIndex++,
|
|
5785
|
-
type: "text",
|
|
5786
|
-
text: typeof item.text === "string" ? item.text : "",
|
|
5787
|
-
status: "streaming"
|
|
5788
|
-
};
|
|
5789
|
-
const blockState2 = { block: block2, status: "streaming" };
|
|
5790
|
-
turn.blocks.push(blockState2);
|
|
5791
|
-
blocksById.set(itemId, blockState2);
|
|
5792
|
-
continue;
|
|
5793
|
-
}
|
|
5794
|
-
if (itemType === "reasoning") {
|
|
5795
|
-
const text = extractCodexReasoningText(item);
|
|
5796
|
-
if (!text) {
|
|
5797
|
-
continue;
|
|
5798
|
-
}
|
|
5799
|
-
const block2 = {
|
|
5800
|
-
id: itemId,
|
|
5801
|
-
turnId,
|
|
5802
|
-
index: turn.nextBlockIndex++,
|
|
5803
|
-
type: "reasoning",
|
|
5804
|
-
text,
|
|
5805
|
-
status: "streaming"
|
|
5806
|
-
};
|
|
5807
|
-
const blockState2 = { block: block2, status: "streaming" };
|
|
5808
|
-
turn.blocks.push(blockState2);
|
|
5809
|
-
blocksById.set(itemId, blockState2);
|
|
5810
|
-
continue;
|
|
5811
|
-
}
|
|
5812
|
-
const block = buildCodexActionBlock(item, turnId, turn.nextBlockIndex++);
|
|
5813
|
-
const blockState = { block, status: "streaming" };
|
|
5814
|
-
turn.blocks.push(blockState);
|
|
5815
|
-
blocksById.set(block.id, blockState);
|
|
5816
|
-
continue;
|
|
5817
|
-
}
|
|
5818
|
-
if (message.method === "item/agentMessage/delta") {
|
|
5819
|
-
const itemId = typeof params?.itemId === "string" ? params.itemId : null;
|
|
5820
|
-
const delta = typeof params?.delta === "string" ? params.delta : "";
|
|
5821
|
-
const blockState = itemId ? blocksById.get(itemId) : undefined;
|
|
5822
|
-
if (blockState?.block.type === "text") {
|
|
5823
|
-
blockState.block.text += delta;
|
|
5824
|
-
}
|
|
5825
|
-
continue;
|
|
5826
|
-
}
|
|
5827
|
-
if (message.method === "item/completed") {
|
|
5828
|
-
const item = params?.item;
|
|
5829
|
-
const turnId = typeof params?.turnId === "string" ? params.turnId : null;
|
|
5830
|
-
const itemType = typeof item?.type === "string" ? item.type : "";
|
|
5831
|
-
const itemId = typeof item?.id === "string" ? item.id : null;
|
|
5832
|
-
if (!turnId || !item || !itemId || !itemType) {
|
|
5833
|
-
continue;
|
|
5834
|
-
}
|
|
5835
|
-
if (itemType === "userMessage") {
|
|
5836
|
-
const turn2 = ensureTurn(turnId);
|
|
5837
|
-
let blockState2 = blocksById.get(itemId);
|
|
5838
|
-
if (!blockState2) {
|
|
5839
|
-
const block = {
|
|
5840
|
-
id: itemId,
|
|
5841
|
-
turnId,
|
|
5842
|
-
index: turn2.nextBlockIndex++,
|
|
5843
|
-
type: "text",
|
|
5844
|
-
text: "",
|
|
5845
|
-
status: "streaming"
|
|
5846
|
-
};
|
|
5847
|
-
blockState2 = { block, status: "streaming" };
|
|
5848
|
-
turn2.blocks.push(blockState2);
|
|
5849
|
-
blocksById.set(itemId, blockState2);
|
|
5850
|
-
}
|
|
5851
|
-
if (blockState2.block.type === "text") {
|
|
5852
|
-
blockState2.block.text = extractCodexUserMessageText(item);
|
|
5853
|
-
}
|
|
5854
|
-
completeBlock(blockState2);
|
|
5855
|
-
continue;
|
|
5856
|
-
}
|
|
5857
|
-
if (itemType === "agentMessage") {
|
|
5858
|
-
const turn2 = ensureTurn(turnId);
|
|
5859
|
-
let blockState2 = blocksById.get(itemId);
|
|
5860
|
-
if (!blockState2) {
|
|
5861
|
-
const block = {
|
|
5862
|
-
id: itemId,
|
|
5863
|
-
turnId,
|
|
5864
|
-
index: turn2.nextBlockIndex++,
|
|
5865
|
-
type: "text",
|
|
5866
|
-
text: "",
|
|
5867
|
-
status: "streaming"
|
|
5868
|
-
};
|
|
5869
|
-
blockState2 = { block, status: "streaming" };
|
|
5870
|
-
turn2.blocks.push(blockState2);
|
|
5871
|
-
blocksById.set(itemId, blockState2);
|
|
5872
|
-
}
|
|
5873
|
-
if (blockState2.block.type === "text" && typeof item.text === "string" && item.text.length > 0) {
|
|
5874
|
-
blockState2.block.text = item.text;
|
|
5875
|
-
}
|
|
5876
|
-
completeBlock(blockState2);
|
|
5877
|
-
continue;
|
|
5878
|
-
}
|
|
5879
|
-
if (itemType === "reasoning") {
|
|
5880
|
-
const text = extractCodexReasoningText(item);
|
|
5881
|
-
if (!text) {
|
|
5882
|
-
continue;
|
|
5883
|
-
}
|
|
5884
|
-
const turn2 = ensureTurn(turnId);
|
|
5885
|
-
let blockState2 = blocksById.get(itemId);
|
|
5886
|
-
if (!blockState2) {
|
|
5887
|
-
const block = {
|
|
5888
|
-
id: itemId,
|
|
5889
|
-
turnId,
|
|
5890
|
-
index: turn2.nextBlockIndex++,
|
|
5891
|
-
type: "reasoning",
|
|
5892
|
-
text,
|
|
5893
|
-
status: "streaming"
|
|
5894
|
-
};
|
|
5895
|
-
blockState2 = { block, status: "streaming" };
|
|
5896
|
-
turn2.blocks.push(blockState2);
|
|
5897
|
-
blocksById.set(itemId, blockState2);
|
|
5898
|
-
}
|
|
5899
|
-
if (blockState2.block.type === "reasoning" && text) {
|
|
5900
|
-
blockState2.block.text = text;
|
|
5901
|
-
}
|
|
5902
|
-
completeBlock(blockState2);
|
|
5903
|
-
continue;
|
|
5904
|
-
}
|
|
5905
|
-
const turn = ensureTurn(turnId);
|
|
5906
|
-
let blockState = blocksById.get(itemId);
|
|
5907
|
-
if (!blockState) {
|
|
5908
|
-
const block = buildCodexActionBlock(item, turnId, turn.nextBlockIndex++);
|
|
5909
|
-
blockState = { block, status: "streaming" };
|
|
5910
|
-
turn.blocks.push(blockState);
|
|
5911
|
-
blocksById.set(itemId, blockState);
|
|
5912
|
-
}
|
|
5913
|
-
if (blockState.block.type === "action") {
|
|
5914
|
-
blockState.block.action.output = renderCodexActionOutput(item);
|
|
5915
|
-
blockState.block.action.status = "completed";
|
|
5916
|
-
}
|
|
5917
|
-
completeBlock(blockState);
|
|
5918
|
-
continue;
|
|
5919
|
-
}
|
|
5920
|
-
if (message.method === "turn/completed") {
|
|
5921
|
-
const turn = params?.turn;
|
|
5922
|
-
if (!turn || typeof turn.id !== "string") {
|
|
5923
|
-
continue;
|
|
5924
|
-
}
|
|
5925
|
-
const turnState = ensureTurn(turn.id);
|
|
5926
|
-
turnState.status = codexTurnStatusToTurnStatus(typeof turn.status === "string" ? turn.status : undefined);
|
|
5927
|
-
turnState.endedAt = Date.now();
|
|
5928
|
-
if (snapshot.currentTurnId === turn.id) {
|
|
5929
|
-
snapshot.currentTurnId = undefined;
|
|
5930
|
-
}
|
|
5931
|
-
snapshot.session.status = turnState.status === "error" ? "error" : "idle";
|
|
5932
|
-
continue;
|
|
5933
|
-
}
|
|
5934
|
-
if (message.method === "error") {
|
|
5935
|
-
snapshot.session.status = "error";
|
|
5936
|
-
}
|
|
5937
|
-
}
|
|
5938
|
-
if (!resolvedThreadId && snapshot.turns.length === 0) {
|
|
5939
|
-
return null;
|
|
5940
|
-
}
|
|
5941
|
-
return snapshot;
|
|
5942
|
-
}
|
|
5943
|
-
function buildCodexRolloutSessionSnapshot(raw, options, targetThreadId, rolloutPath) {
|
|
5944
|
-
const lines = raw.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
5945
|
-
let resolvedThreadId = targetThreadId?.trim() || null;
|
|
5946
|
-
const snapshot = {
|
|
5947
|
-
session: {
|
|
5948
|
-
id: options.sessionId,
|
|
5949
|
-
name: options.agentName,
|
|
5950
|
-
adapterType: "codex_app_server",
|
|
5951
|
-
status: resolvedThreadId ? "idle" : "connecting",
|
|
5952
|
-
cwd: options.cwd
|
|
5953
|
-
},
|
|
5954
|
-
turns: []
|
|
5955
|
-
};
|
|
5956
|
-
setCodexProviderMeta(snapshot, resolvedThreadId, rolloutPath ?? null);
|
|
5957
|
-
const turnsById = new Map;
|
|
5958
|
-
const blocksByCallId = new Map;
|
|
5959
|
-
let currentTurnId = null;
|
|
5960
|
-
const ensureTurn = (turnId, startedAt) => {
|
|
5961
|
-
const existing = turnsById.get(turnId);
|
|
5962
|
-
if (existing) {
|
|
5963
|
-
if (startedAt && !existing.startedAt) {
|
|
5964
|
-
existing.startedAt = startedAt;
|
|
5965
|
-
}
|
|
5966
|
-
return existing;
|
|
5967
|
-
}
|
|
5968
|
-
const turn = {
|
|
5969
|
-
id: turnId,
|
|
5970
|
-
status: "streaming",
|
|
5971
|
-
blocks: [],
|
|
5972
|
-
startedAt: startedAt ?? Date.now(),
|
|
5973
|
-
nextBlockIndex: 0
|
|
5974
|
-
};
|
|
5975
|
-
turnsById.set(turnId, turn);
|
|
5976
|
-
snapshot.turns.push(turn);
|
|
5977
|
-
snapshot.currentTurnId = turnId;
|
|
5978
|
-
snapshot.session.status = "active";
|
|
5979
|
-
return turn;
|
|
5980
|
-
};
|
|
5981
|
-
for (const line of lines) {
|
|
5982
|
-
const message = parseJsonRecord(line);
|
|
5983
|
-
if (!message) {
|
|
5984
|
-
continue;
|
|
5985
|
-
}
|
|
5986
|
-
const timestamp = parseCodexTimestamp(message.timestamp) ?? Date.now();
|
|
5987
|
-
const entryType = typeof message.type === "string" ? message.type : "";
|
|
5988
|
-
const payload = message.payload && typeof message.payload === "object" && !Array.isArray(message.payload) ? message.payload : undefined;
|
|
5989
|
-
if (!payload) {
|
|
5990
|
-
continue;
|
|
5991
|
-
}
|
|
5992
|
-
if (entryType === "session_meta") {
|
|
5993
|
-
const sessionThreadId = typeof payload.id === "string" ? payload.id : null;
|
|
5994
|
-
if (sessionThreadId) {
|
|
5995
|
-
if (resolvedThreadId && sessionThreadId !== resolvedThreadId) {
|
|
5996
|
-
return null;
|
|
5997
|
-
}
|
|
5998
|
-
resolvedThreadId = sessionThreadId;
|
|
5999
|
-
}
|
|
6000
|
-
if (typeof payload.cwd === "string" && payload.cwd.trim()) {
|
|
6001
|
-
snapshot.session.cwd = payload.cwd;
|
|
6002
|
-
}
|
|
6003
|
-
setCodexProviderMeta(snapshot, resolvedThreadId, rolloutPath ?? null);
|
|
6004
|
-
snapshot.session.status = resolvedThreadId ? "idle" : snapshot.session.status;
|
|
6005
|
-
continue;
|
|
6006
|
-
}
|
|
6007
|
-
if (entryType === "turn_context") {
|
|
6008
|
-
if (typeof payload.cwd === "string" && payload.cwd.trim()) {
|
|
6009
|
-
snapshot.session.cwd = payload.cwd;
|
|
6010
|
-
}
|
|
6011
|
-
if (typeof payload.model === "string" && payload.model.trim()) {
|
|
6012
|
-
snapshot.session.model = payload.model;
|
|
6013
|
-
}
|
|
6014
|
-
continue;
|
|
6015
|
-
}
|
|
6016
|
-
if (entryType === "event_msg") {
|
|
6017
|
-
const payloadType2 = typeof payload.type === "string" ? payload.type : "";
|
|
6018
|
-
if (payloadType2 === "task_started") {
|
|
6019
|
-
const turnId = typeof payload.turn_id === "string" ? payload.turn_id : null;
|
|
6020
|
-
if (!turnId) {
|
|
6021
|
-
continue;
|
|
6022
|
-
}
|
|
6023
|
-
currentTurnId = turnId;
|
|
6024
|
-
ensureTurn(turnId, parseCodexTimestamp(payload.started_at) ?? timestamp);
|
|
6025
|
-
snapshot.currentTurnId = turnId;
|
|
6026
|
-
snapshot.session.status = "active";
|
|
6027
|
-
continue;
|
|
6028
|
-
}
|
|
6029
|
-
if (payloadType2 === "task_complete" || payloadType2 === "turn_aborted") {
|
|
6030
|
-
const turnId = typeof payload.turn_id === "string" ? payload.turn_id : currentTurnId;
|
|
6031
|
-
if (!turnId) {
|
|
6032
|
-
continue;
|
|
6033
|
-
}
|
|
6034
|
-
const turn2 = ensureTurn(turnId);
|
|
6035
|
-
turn2.status = payloadType2 === "task_complete" ? "completed" : payload.reason === "interrupted" ? "interrupted" : "error";
|
|
6036
|
-
turn2.endedAt = parseCodexTimestamp(payload.completed_at) ?? timestamp;
|
|
6037
|
-
finalizeCodexTurnBlocks(turn2, turn2.status);
|
|
6038
|
-
if (snapshot.currentTurnId === turnId) {
|
|
6039
|
-
snapshot.currentTurnId = undefined;
|
|
6040
|
-
}
|
|
6041
|
-
currentTurnId = currentTurnId === turnId ? null : currentTurnId;
|
|
6042
|
-
snapshot.session.status = turn2.status === "error" ? "error" : "idle";
|
|
6043
|
-
}
|
|
6044
|
-
continue;
|
|
6045
|
-
}
|
|
6046
|
-
if (entryType !== "response_item" || !currentTurnId) {
|
|
6047
|
-
continue;
|
|
6048
|
-
}
|
|
6049
|
-
const turn = ensureTurn(currentTurnId);
|
|
6050
|
-
const payloadType = typeof payload.type === "string" ? payload.type : "";
|
|
6051
|
-
if (payloadType === "message" && payload.role === "user") {
|
|
6052
|
-
const text = extractCodexMessageText(payload);
|
|
6053
|
-
if (!text) {
|
|
6054
|
-
continue;
|
|
6055
|
-
}
|
|
6056
|
-
const block = {
|
|
6057
|
-
id: `${turn.id}:text:${turn.nextBlockIndex}`,
|
|
6058
|
-
turnId: turn.id,
|
|
6059
|
-
index: turn.nextBlockIndex++,
|
|
6060
|
-
type: "text",
|
|
6061
|
-
text,
|
|
6062
|
-
status: "completed"
|
|
6063
|
-
};
|
|
6064
|
-
turn.blocks.push({ block, status: "completed" });
|
|
6065
|
-
continue;
|
|
6066
|
-
}
|
|
6067
|
-
if (payloadType === "message" && payload.role === "assistant") {
|
|
6068
|
-
const text = extractCodexMessageText(payload);
|
|
6069
|
-
if (!text) {
|
|
6070
|
-
continue;
|
|
6071
|
-
}
|
|
6072
|
-
const block = {
|
|
6073
|
-
id: `${turn.id}:text:${turn.nextBlockIndex}`,
|
|
6074
|
-
turnId: turn.id,
|
|
6075
|
-
index: turn.nextBlockIndex++,
|
|
6076
|
-
type: "text",
|
|
6077
|
-
text,
|
|
6078
|
-
status: "completed"
|
|
6079
|
-
};
|
|
6080
|
-
turn.blocks.push({ block, status: "completed" });
|
|
6081
|
-
continue;
|
|
6082
|
-
}
|
|
6083
|
-
if (payloadType === "reasoning") {
|
|
6084
|
-
const text = extractCodexReasoningText(payload);
|
|
6085
|
-
if (!text) {
|
|
6086
|
-
continue;
|
|
6087
|
-
}
|
|
6088
|
-
const block = {
|
|
6089
|
-
id: `${turn.id}:reasoning:${turn.nextBlockIndex}`,
|
|
6090
|
-
turnId: turn.id,
|
|
6091
|
-
index: turn.nextBlockIndex++,
|
|
6092
|
-
type: "reasoning",
|
|
6093
|
-
text,
|
|
6094
|
-
status: "completed"
|
|
6095
|
-
};
|
|
6096
|
-
turn.blocks.push({ block, status: "completed" });
|
|
6097
|
-
continue;
|
|
6098
|
-
}
|
|
6099
|
-
if (payloadType === "function_call" || payloadType === "custom_tool_call" || payloadType === "web_search_call") {
|
|
6100
|
-
const block = buildCodexRolloutActionBlock(payload, turn.id, turn.nextBlockIndex++);
|
|
6101
|
-
const blockState = { block, status: "streaming" };
|
|
6102
|
-
turn.blocks.push(blockState);
|
|
6103
|
-
blocksByCallId.set(block.id, blockState);
|
|
6104
|
-
continue;
|
|
6105
|
-
}
|
|
6106
|
-
if (payloadType === "function_call_output" || payloadType === "custom_tool_call_output") {
|
|
6107
|
-
const callId = typeof payload.call_id === "string" ? payload.call_id : null;
|
|
6108
|
-
if (!callId) {
|
|
6109
|
-
continue;
|
|
6110
|
-
}
|
|
6111
|
-
let blockState = blocksByCallId.get(callId);
|
|
6112
|
-
if (!blockState) {
|
|
6113
|
-
const block = buildCodexRolloutActionBlock({
|
|
6114
|
-
type: "tool_call",
|
|
6115
|
-
call_id: callId,
|
|
6116
|
-
name: "unknown"
|
|
6117
|
-
}, turn.id, turn.nextBlockIndex++);
|
|
6118
|
-
blockState = { block, status: "streaming" };
|
|
6119
|
-
turn.blocks.push(blockState);
|
|
6120
|
-
blocksByCallId.set(callId, blockState);
|
|
6121
|
-
}
|
|
6122
|
-
if (blockState.block.type === "action") {
|
|
6123
|
-
blockState.block.action.output = stringifyCodexItem(payload.output);
|
|
6124
|
-
blockState.block.action.status = "completed";
|
|
6125
|
-
}
|
|
6126
|
-
blockState.status = "completed";
|
|
6127
|
-
blockState.block.status = "completed";
|
|
6128
|
-
}
|
|
6129
|
-
}
|
|
6130
|
-
if (!resolvedThreadId && snapshot.turns.length === 0) {
|
|
6131
|
-
return null;
|
|
6132
|
-
}
|
|
6133
|
-
setCodexProviderMeta(snapshot, resolvedThreadId, rolloutPath ?? null);
|
|
6134
|
-
snapshot.session.status = snapshot.currentTurnId ? "active" : snapshot.session.status;
|
|
6135
|
-
return snapshot;
|
|
6136
|
-
}
|
|
6137
4968
|
function isMissingCodexRolloutError(error) {
|
|
6138
4969
|
const message = errorMessage2(error).toLowerCase();
|
|
6139
4970
|
return message.includes("no rollout found for thread id");
|
|
@@ -6780,48 +5611,10 @@ async function ensureCodexAppServerAgentOnline(options) {
|
|
|
6780
5611
|
session.update(options);
|
|
6781
5612
|
return session.ensureOnline();
|
|
6782
5613
|
}
|
|
6783
|
-
async function invokeCodexAppServerAgent(options) {
|
|
6784
|
-
const session = getOrCreateSession2(options);
|
|
6785
|
-
session.update(options);
|
|
6786
|
-
return session.invoke(options.prompt, options.timeoutMs);
|
|
6787
|
-
}
|
|
6788
|
-
async function sendCodexAppServerAgent(options) {
|
|
6789
|
-
const session = getOrCreateSession2(options);
|
|
6790
|
-
session.update(options);
|
|
6791
|
-
if (session.hasActiveTurn()) {
|
|
6792
|
-
return session.steerAndWait(options.prompt, options.timeoutMs);
|
|
6793
|
-
}
|
|
6794
|
-
return session.invoke(options.prompt, options.timeoutMs);
|
|
6795
|
-
}
|
|
6796
5614
|
function isCodexAppServerAgentAlive(options) {
|
|
6797
5615
|
const session = sessions2.get(sessionKey2(options));
|
|
6798
5616
|
return Boolean(session?.isAlive());
|
|
6799
5617
|
}
|
|
6800
|
-
async function getCodexAppServerAgentSnapshot(options) {
|
|
6801
|
-
const stdoutLogPath = join6(options.logsDirectory, "stdout.log");
|
|
6802
|
-
const threadIdPath = join6(options.runtimeDirectory, "codex-thread-id.txt");
|
|
6803
|
-
const statePath = join6(options.runtimeDirectory, "state.json");
|
|
6804
|
-
const [rawLog, persistedThreadId, persistedState] = await Promise.all([
|
|
6805
|
-
readOptionalFile2(stdoutLogPath),
|
|
6806
|
-
readOptionalFile2(threadIdPath),
|
|
6807
|
-
readOptionalJsonRecord(statePath)
|
|
6808
|
-
]);
|
|
6809
|
-
const resolvedThreadId = options.threadId ?? persistedThreadId ?? metadataString(persistedState ?? undefined, "threadId") ?? undefined;
|
|
6810
|
-
const persistedThreadPath = metadataString(persistedState ?? undefined, "threadPath");
|
|
6811
|
-
if (persistedThreadPath) {
|
|
6812
|
-
const rawRollout = await readOptionalFile2(persistedThreadPath);
|
|
6813
|
-
if (rawRollout) {
|
|
6814
|
-
const rolloutSnapshot = buildCodexRolloutSessionSnapshot(rawRollout, options, resolvedThreadId, persistedThreadPath);
|
|
6815
|
-
if (rolloutSnapshot) {
|
|
6816
|
-
return rolloutSnapshot;
|
|
6817
|
-
}
|
|
6818
|
-
}
|
|
6819
|
-
}
|
|
6820
|
-
if (!rawLog) {
|
|
6821
|
-
return null;
|
|
6822
|
-
}
|
|
6823
|
-
return buildCodexAppServerSessionSnapshot(rawLog, options, resolvedThreadId);
|
|
6824
|
-
}
|
|
6825
5618
|
async function shutdownCodexAppServerAgent(options, shutdownOptions = {}) {
|
|
6826
5619
|
const key = sessionKey2(options);
|
|
6827
5620
|
const session = sessions2.get(key);
|
|
@@ -6841,49 +5634,6 @@ var init_codex_app_server = __esm(() => {
|
|
|
6841
5634
|
});
|
|
6842
5635
|
|
|
6843
5636
|
// ../runtime/src/collaboration-contract.ts
|
|
6844
|
-
function metadataValue(metadata, key) {
|
|
6845
|
-
return metadata?.[key];
|
|
6846
|
-
}
|
|
6847
|
-
function recordFromInvocation(invocation, key) {
|
|
6848
|
-
const contextRecord = metadataValue(invocation.context, key);
|
|
6849
|
-
if (typeof contextRecord !== "undefined") {
|
|
6850
|
-
return contextRecord;
|
|
6851
|
-
}
|
|
6852
|
-
const nestedContext = metadataValue(invocation.context, "collaboration");
|
|
6853
|
-
if (nestedContext && typeof nestedContext === "object" && !Array.isArray(nestedContext)) {
|
|
6854
|
-
const nestedValue = metadataValue(nestedContext, key);
|
|
6855
|
-
if (typeof nestedValue !== "undefined") {
|
|
6856
|
-
return nestedValue;
|
|
6857
|
-
}
|
|
6858
|
-
}
|
|
6859
|
-
const metadataRecord2 = metadataValue(invocation.metadata, key);
|
|
6860
|
-
if (typeof metadataRecord2 !== "undefined") {
|
|
6861
|
-
return metadataRecord2;
|
|
6862
|
-
}
|
|
6863
|
-
const nestedMetadata = metadataValue(invocation.metadata, "collaboration");
|
|
6864
|
-
if (nestedMetadata && typeof nestedMetadata === "object" && !Array.isArray(nestedMetadata)) {
|
|
6865
|
-
return metadataValue(nestedMetadata, key);
|
|
6866
|
-
}
|
|
6867
|
-
return;
|
|
6868
|
-
}
|
|
6869
|
-
function stringFromInvocation(invocation, key) {
|
|
6870
|
-
const value = recordFromInvocation(invocation, key);
|
|
6871
|
-
return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
|
|
6872
|
-
}
|
|
6873
|
-
function waitingOnLabel(value) {
|
|
6874
|
-
if (typeof value === "string" && value.trim().length > 0) {
|
|
6875
|
-
return value.trim();
|
|
6876
|
-
}
|
|
6877
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
6878
|
-
return;
|
|
6879
|
-
}
|
|
6880
|
-
const waitingOn = value;
|
|
6881
|
-
const kind = typeof waitingOn.kind === "string" ? waitingOn.kind : undefined;
|
|
6882
|
-
const label = typeof waitingOn.label === "string" ? waitingOn.label.trim() : "";
|
|
6883
|
-
const targetId = typeof waitingOn.targetId === "string" ? waitingOn.targetId.trim() : "";
|
|
6884
|
-
const parts = [label || kind, targetId || undefined].filter(Boolean);
|
|
6885
|
-
return parts.length > 0 ? parts.join(" \xB7 ") : undefined;
|
|
6886
|
-
}
|
|
6887
5637
|
function buildCollaborationContractPrompt(agentId) {
|
|
6888
5638
|
return [
|
|
6889
5639
|
"Collaboration contract:",
|
|
@@ -6900,38 +5650,6 @@ function buildCollaborationContractPrompt(agentId) {
|
|
|
6900
5650
|
].join(`
|
|
6901
5651
|
`);
|
|
6902
5652
|
}
|
|
6903
|
-
function buildInvocationCollaborationContextPrompt(invocation) {
|
|
6904
|
-
const recordId = stringFromInvocation(invocation, "recordId") ?? stringFromInvocation(invocation, "collaborationRecordId");
|
|
6905
|
-
const kind = stringFromInvocation(invocation, "kind") ?? stringFromInvocation(invocation, "collaborationKind");
|
|
6906
|
-
const state = stringFromInvocation(invocation, "state") ?? stringFromInvocation(invocation, "collaborationState");
|
|
6907
|
-
const ownerId = stringFromInvocation(invocation, "ownerId");
|
|
6908
|
-
const nextMoveOwnerId = stringFromInvocation(invocation, "nextMoveOwnerId");
|
|
6909
|
-
const wakeReason = stringFromInvocation(invocation, "wakeReason");
|
|
6910
|
-
const targetAgentId = stringFromInvocation(invocation, "targetAgentId");
|
|
6911
|
-
const waitingOn = waitingOnLabel(recordFromInvocation(invocation, "waitingOn") ?? recordFromInvocation(invocation, "waiting_on"));
|
|
6912
|
-
const acceptanceState = stringFromInvocation(invocation, "acceptanceState");
|
|
6913
|
-
const requestedById = stringFromInvocation(invocation, "requestedById");
|
|
6914
|
-
const askedById = stringFromInvocation(invocation, "askedById");
|
|
6915
|
-
const askedOfId = stringFromInvocation(invocation, "askedOfId");
|
|
6916
|
-
const lines = [
|
|
6917
|
-
recordId ? ` - Record: ${kind ? `${kind} ` : ""}${recordId}` : undefined,
|
|
6918
|
-
state ? ` - State: ${state}` : undefined,
|
|
6919
|
-
ownerId ? ` - Owner: ${ownerId}` : undefined,
|
|
6920
|
-
nextMoveOwnerId ? ` - Next move owner: ${nextMoveOwnerId}` : undefined,
|
|
6921
|
-
wakeReason ? ` - Wake reason: ${wakeReason}` : undefined,
|
|
6922
|
-
targetAgentId ? ` - Wake target: ${targetAgentId}` : undefined,
|
|
6923
|
-
waitingOn ? ` - Waiting on: ${waitingOn}` : undefined,
|
|
6924
|
-
acceptanceState ? ` - Acceptance: ${acceptanceState}` : undefined,
|
|
6925
|
-
requestedById ? ` - Requested by: ${requestedById}` : undefined,
|
|
6926
|
-
askedById ? ` - Asked by: ${askedById}` : undefined,
|
|
6927
|
-
askedOfId ? ` - Asked of: ${askedOfId}` : undefined
|
|
6928
|
-
].filter((value) => Boolean(value));
|
|
6929
|
-
if (lines.length === 0) {
|
|
6930
|
-
return;
|
|
6931
|
-
}
|
|
6932
|
-
return ["Collaboration context:", ...lines].join(`
|
|
6933
|
-
`);
|
|
6934
|
-
}
|
|
6935
5653
|
|
|
6936
5654
|
// ../runtime/src/broker-service.ts
|
|
6937
5655
|
import { spawnSync } from "child_process";
|
|
@@ -7460,43 +6178,6 @@ var init_local_agent_template = __esm(() => {
|
|
|
7460
6178
|
});
|
|
7461
6179
|
|
|
7462
6180
|
// ../runtime/src/local-agents.ts
|
|
7463
|
-
var exports_local_agents = {};
|
|
7464
|
-
__export(exports_local_agents, {
|
|
7465
|
-
updateLocalAgentConfig: () => updateLocalAgentConfig,
|
|
7466
|
-
stripLocalAgentReplyMetadata: () => stripLocalAgentReplyMetadata,
|
|
7467
|
-
stopLocalAgent: () => stopLocalAgent,
|
|
7468
|
-
stopAllLocalAgents: () => stopAllLocalAgents,
|
|
7469
|
-
startLocalAgent: () => startLocalAgent,
|
|
7470
|
-
shutdownLocalSessionEndpoint: () => shutdownLocalSessionEndpoint,
|
|
7471
|
-
shouldDisableGeneratedCodexEndpoint: () => shouldDisableGeneratedCodexEndpoint,
|
|
7472
|
-
sendTmuxPrompt: () => sendTmuxPrompt,
|
|
7473
|
-
restartLocalAgent: () => restartLocalAgent,
|
|
7474
|
-
restartAllLocalAgents: () => restartAllLocalAgents,
|
|
7475
|
-
resolveLocalAgentIdentity: () => resolveLocalAgentIdentity,
|
|
7476
|
-
resolveLocalAgentByName: () => resolveLocalAgentByName,
|
|
7477
|
-
renderLocalAgentSystemPromptTemplate: () => renderLocalAgentSystemPromptTemplate,
|
|
7478
|
-
loadRegisteredLocalAgentBindings: () => loadRegisteredLocalAgentBindings,
|
|
7479
|
-
listLocalAgents: () => listLocalAgents,
|
|
7480
|
-
isLocalAgentSessionAlive: () => isLocalAgentSessionAlive,
|
|
7481
|
-
isLocalAgentEndpointAlive: () => isLocalAgentEndpointAlive,
|
|
7482
|
-
invokeLocalAgentEndpoint: () => invokeLocalAgentEndpoint,
|
|
7483
|
-
interruptLocalAgent: () => interruptLocalAgent,
|
|
7484
|
-
inferLocalAgentBinding: () => inferLocalAgentBinding,
|
|
7485
|
-
getLocalAgentSessionSnapshot: () => getLocalAgentSessionSnapshot,
|
|
7486
|
-
getLocalAgentEndpointSessionSnapshot: () => getLocalAgentEndpointSessionSnapshot,
|
|
7487
|
-
getLocalAgentConfig: () => getLocalAgentConfig,
|
|
7488
|
-
ensureLocalSessionEndpointOnline: () => ensureLocalSessionEndpointOnline,
|
|
7489
|
-
ensureLocalAgentBindingOnline: () => ensureLocalAgentBindingOnline,
|
|
7490
|
-
buildTmuxLaunchShellCommand: () => buildTmuxLaunchShellCommand,
|
|
7491
|
-
buildLocalAgentSystemPromptTemplate: () => buildLocalAgentSystemPromptTemplate,
|
|
7492
|
-
buildLocalAgentSystemPrompt: () => buildLocalAgentSystemPrompt,
|
|
7493
|
-
buildLocalAgentNudge: () => buildLocalAgentNudge,
|
|
7494
|
-
buildLocalAgentDirectInvocationPrompt: () => buildLocalAgentDirectInvocationPrompt,
|
|
7495
|
-
buildAttachedSessionInvocationPrompt: () => buildAttachedSessionInvocationPrompt,
|
|
7496
|
-
answerLocalAgentSessionQuestion: () => answerLocalAgentSessionQuestion,
|
|
7497
|
-
SUPPORTED_LOCAL_AGENT_HARNESSES: () => SUPPORTED_LOCAL_AGENT_HARNESSES
|
|
7498
|
-
});
|
|
7499
|
-
import { randomUUID as randomUUID2 } from "crypto";
|
|
7500
6181
|
import { execFileSync as execFileSync3, execSync } from "child_process";
|
|
7501
6182
|
import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
|
|
7502
6183
|
import { mkdir as mkdir5, rm as rm4, stat as stat3, writeFile as writeFile5 } from "fs/promises";
|
|
@@ -7527,21 +6208,9 @@ function resolveBrokerUrl() {
|
|
|
7527
6208
|
function nowSeconds2() {
|
|
7528
6209
|
return Math.floor(Date.now() / 1000);
|
|
7529
6210
|
}
|
|
7530
|
-
function normalizeBrokerTimestamp(value) {
|
|
7531
|
-
return value > 10000000000 ? Math.floor(value / 1000) : value;
|
|
7532
|
-
}
|
|
7533
6211
|
function brokerRelayCommand() {
|
|
7534
6212
|
return `node ${JSON.stringify(join8(OPENSCOUT_REPO_ROOT, "packages", "cli", "bin", "scout.mjs"))}`;
|
|
7535
6213
|
}
|
|
7536
|
-
function sleep2(ms) {
|
|
7537
|
-
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
7538
|
-
}
|
|
7539
|
-
function createLocalAgentFlightId() {
|
|
7540
|
-
return `f-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;
|
|
7541
|
-
}
|
|
7542
|
-
function escapeRegExp(value) {
|
|
7543
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
7544
|
-
}
|
|
7545
6214
|
function titleCaseLocalAgentName(value) {
|
|
7546
6215
|
return value.split(/[-_.\s]+/).filter(Boolean).map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1)).join(" ");
|
|
7547
6216
|
}
|
|
@@ -7786,13 +6455,6 @@ function expandHomePath3(value) {
|
|
|
7786
6455
|
function normalizeProjectPath(value) {
|
|
7787
6456
|
return resolve6(expandHomePath3(value.trim() || "."));
|
|
7788
6457
|
}
|
|
7789
|
-
function compactHomePath(value) {
|
|
7790
|
-
const home = process.env.HOME;
|
|
7791
|
-
if (!home) {
|
|
7792
|
-
return value;
|
|
7793
|
-
}
|
|
7794
|
-
return value.startsWith(home) ? value.replace(home, "~") : value;
|
|
7795
|
-
}
|
|
7796
6458
|
function normalizeTmuxSessionName2(value, agentId) {
|
|
7797
6459
|
const fallback = `relay-${agentId}`;
|
|
7798
6460
|
const trimmed = value?.trim() ?? "";
|
|
@@ -8038,134 +6700,6 @@ function relayAgentOverrideFromLocalAgentRecord(agentId, record, existing) {
|
|
|
8038
6700
|
}
|
|
8039
6701
|
};
|
|
8040
6702
|
}
|
|
8041
|
-
function buildLocalAgentConfigState(agentId, record) {
|
|
8042
|
-
return {
|
|
8043
|
-
agentId,
|
|
8044
|
-
editable: true,
|
|
8045
|
-
systemPrompt: record.systemPrompt || buildLocalAgentSystemPromptTemplate(),
|
|
8046
|
-
runtime: {
|
|
8047
|
-
cwd: compactHomePath(record.cwd),
|
|
8048
|
-
harness: normalizeLocalAgentHarness(record.harness),
|
|
8049
|
-
transport: normalizeLocalAgentTransport(record.transport, normalizeLocalAgentHarness(record.harness)),
|
|
8050
|
-
sessionId: record.tmuxSession,
|
|
8051
|
-
wakePolicy: "on_demand"
|
|
8052
|
-
},
|
|
8053
|
-
launchArgs: normalizeLocalAgentLaunchArgs(record.launchArgs),
|
|
8054
|
-
capabilities: normalizeLocalAgentCapabilities(record.capabilities),
|
|
8055
|
-
applyMode: "restart",
|
|
8056
|
-
templateHint: LOCAL_AGENT_SYSTEM_PROMPT_TEMPLATE_HINT
|
|
8057
|
-
};
|
|
8058
|
-
}
|
|
8059
|
-
async function assertDirectoryExists(directory) {
|
|
8060
|
-
const stats = await stat3(directory);
|
|
8061
|
-
if (!stats.isDirectory()) {
|
|
8062
|
-
throw new Error(`${directory} is not a directory.`);
|
|
8063
|
-
}
|
|
8064
|
-
}
|
|
8065
|
-
async function resolveConfiguredLocalAgentRecord(agentId) {
|
|
8066
|
-
const overrides = await readRelayAgentOverrides();
|
|
8067
|
-
const override = overrides[agentId];
|
|
8068
|
-
if (override) {
|
|
8069
|
-
return localAgentRecordFromRelayAgentOverride(agentId, override);
|
|
8070
|
-
}
|
|
8071
|
-
const registry = await readLocalAgentRegistry();
|
|
8072
|
-
const record = registry[agentId];
|
|
8073
|
-
return record ? normalizeLocalAgentRecord(agentId, record) : null;
|
|
8074
|
-
}
|
|
8075
|
-
async function getLocalAgentConfig(agentId) {
|
|
8076
|
-
const record = await resolveConfiguredLocalAgentRecord(agentId);
|
|
8077
|
-
if (!record) {
|
|
8078
|
-
return null;
|
|
8079
|
-
}
|
|
8080
|
-
return buildLocalAgentConfigState(agentId, record);
|
|
8081
|
-
}
|
|
8082
|
-
async function getLocalAgentSessionSnapshot(agentId) {
|
|
8083
|
-
const record = await resolveConfiguredLocalAgentRecord(agentId);
|
|
8084
|
-
if (!record) {
|
|
8085
|
-
return null;
|
|
8086
|
-
}
|
|
8087
|
-
if (record.transport === "codex_app_server") {
|
|
8088
|
-
return getCodexAppServerAgentSnapshot(buildCodexAgentSessionOptions(agentId, record));
|
|
8089
|
-
}
|
|
8090
|
-
if (record.transport === "claude_stream_json") {
|
|
8091
|
-
return getClaudeStreamJsonAgentSnapshot(buildClaudeAgentSessionOptions(agentId, record));
|
|
8092
|
-
}
|
|
8093
|
-
return null;
|
|
8094
|
-
}
|
|
8095
|
-
async function getLocalAgentEndpointSessionSnapshot(endpoint) {
|
|
8096
|
-
if (endpoint.transport === "codex_app_server") {
|
|
8097
|
-
return getCodexAppServerAgentSnapshot(buildCodexEndpointSessionOptions(endpoint));
|
|
8098
|
-
}
|
|
8099
|
-
if (endpoint.transport === "claude_stream_json") {
|
|
8100
|
-
return getClaudeStreamJsonAgentSnapshot(buildClaudeEndpointSessionOptions(endpoint));
|
|
8101
|
-
}
|
|
8102
|
-
return null;
|
|
8103
|
-
}
|
|
8104
|
-
async function ensureLocalSessionEndpointOnline(endpoint) {
|
|
8105
|
-
if (endpoint.transport === "codex_app_server") {
|
|
8106
|
-
await ensureCodexAppServerAgentOnline(buildCodexEndpointSessionOptions(endpoint));
|
|
8107
|
-
return;
|
|
8108
|
-
}
|
|
8109
|
-
if (endpoint.transport === "claude_stream_json") {
|
|
8110
|
-
await ensureClaudeStreamJsonAgentOnline(buildClaudeEndpointSessionOptions(endpoint));
|
|
8111
|
-
}
|
|
8112
|
-
}
|
|
8113
|
-
async function shutdownLocalSessionEndpoint(endpoint) {
|
|
8114
|
-
if (endpoint.transport === "codex_app_server") {
|
|
8115
|
-
await shutdownCodexAppServerAgent(buildCodexEndpointSessionOptions(endpoint));
|
|
8116
|
-
return;
|
|
8117
|
-
}
|
|
8118
|
-
if (endpoint.transport === "claude_stream_json") {
|
|
8119
|
-
await shutdownClaudeStreamJsonAgent(buildClaudeEndpointSessionOptions(endpoint));
|
|
8120
|
-
}
|
|
8121
|
-
}
|
|
8122
|
-
async function answerLocalAgentSessionQuestion(agentId, input) {
|
|
8123
|
-
const record = await resolveConfiguredLocalAgentRecord(agentId);
|
|
8124
|
-
if (!record) {
|
|
8125
|
-
throw new Error(`Agent ${agentId} is not configured.`);
|
|
8126
|
-
}
|
|
8127
|
-
if (record.transport !== "claude_stream_json") {
|
|
8128
|
-
throw new Error(`Agent ${agentId} does not support direct question answers for transport ${record.transport}.`);
|
|
8129
|
-
}
|
|
8130
|
-
await answerClaudeStreamJsonQuestion(buildClaudeAgentSessionOptions(agentId, record), input);
|
|
8131
|
-
}
|
|
8132
|
-
async function updateLocalAgentConfig(agentId, input) {
|
|
8133
|
-
const [registry, overrides] = await Promise.all([
|
|
8134
|
-
readLocalAgentRegistry(),
|
|
8135
|
-
readRelayAgentOverrides()
|
|
8136
|
-
]);
|
|
8137
|
-
const record = registry[agentId] ?? (overrides[agentId] ? localAgentRecordFromRelayAgentOverride(agentId, overrides[agentId]) : undefined);
|
|
8138
|
-
if (!record) {
|
|
8139
|
-
return null;
|
|
8140
|
-
}
|
|
8141
|
-
const cwd = normalizeProjectPath(input.runtime.cwd || record.cwd);
|
|
8142
|
-
await assertDirectoryExists(cwd);
|
|
8143
|
-
const nextHarness = normalizeLocalAgentHarness(input.runtime.harness);
|
|
8144
|
-
const nextTransport = normalizeLocalAgentTransport(input.runtime.transport ?? record.transport, nextHarness);
|
|
8145
|
-
const nextRecord = normalizeLocalAgentRecord(agentId, {
|
|
8146
|
-
...record,
|
|
8147
|
-
cwd,
|
|
8148
|
-
tmuxSession: input.runtime.sessionId,
|
|
8149
|
-
harness: nextHarness,
|
|
8150
|
-
defaultHarness: nextHarness,
|
|
8151
|
-
harnessProfiles: {
|
|
8152
|
-
...record.harnessProfiles ?? {},
|
|
8153
|
-
[normalizeManagedHarness2(input.runtime.harness, "claude")]: {
|
|
8154
|
-
cwd,
|
|
8155
|
-
transport: nextTransport,
|
|
8156
|
-
sessionId: normalizeTmuxSessionName2(input.runtime.sessionId, `${agentId}-${normalizeManagedHarness2(input.runtime.harness, "claude")}`),
|
|
8157
|
-
launchArgs: input.launchArgs
|
|
8158
|
-
}
|
|
8159
|
-
},
|
|
8160
|
-
transport: nextTransport,
|
|
8161
|
-
systemPrompt: input.systemPrompt.trim() || undefined,
|
|
8162
|
-
launchArgs: input.launchArgs,
|
|
8163
|
-
capabilities: input.capabilities
|
|
8164
|
-
});
|
|
8165
|
-
registry[agentId] = nextRecord;
|
|
8166
|
-
await writeLocalAgentRegistry(registry);
|
|
8167
|
-
return buildLocalAgentConfigState(agentId, nextRecord);
|
|
8168
|
-
}
|
|
8169
6703
|
function buildCodexAgentSessionOptions(agentName, record, systemPrompt) {
|
|
8170
6704
|
return {
|
|
8171
6705
|
agentName,
|
|
@@ -8188,72 +6722,6 @@ function buildClaudeAgentSessionOptions(agentName, record, systemPrompt) {
|
|
|
8188
6722
|
launchArgs: normalizeLocalAgentLaunchArgs(record.launchArgs)
|
|
8189
6723
|
};
|
|
8190
6724
|
}
|
|
8191
|
-
function endpointMetadataString(endpoint, key) {
|
|
8192
|
-
const value = endpoint.metadata?.[key];
|
|
8193
|
-
return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
|
|
8194
|
-
}
|
|
8195
|
-
function endpointInvocationPrompt(endpoint, agentName, invocation) {
|
|
8196
|
-
const source = endpointMetadataString(endpoint, "source");
|
|
8197
|
-
const externalSource = endpointMetadataString(endpoint, "externalSource");
|
|
8198
|
-
const attachedTransport = endpointMetadataString(endpoint, "attachedTransport");
|
|
8199
|
-
const sessionBacked = endpoint.metadata?.sessionBacked === true;
|
|
8200
|
-
if (invocation.action === "consult" && (sessionBacked || source === "local-session" || externalSource === "local-session" || attachedTransport === "codex_app_server" || attachedTransport === "claude_stream_json")) {
|
|
8201
|
-
return invocation.task;
|
|
8202
|
-
}
|
|
8203
|
-
if (sessionBacked) {
|
|
8204
|
-
return buildAttachedSessionInvocationPrompt(invocation);
|
|
8205
|
-
}
|
|
8206
|
-
return buildLocalAgentDirectInvocationPrompt(agentName, invocation);
|
|
8207
|
-
}
|
|
8208
|
-
function isSessionBackedEndpoint(endpoint) {
|
|
8209
|
-
const source = endpointMetadataString(endpoint, "source");
|
|
8210
|
-
const externalSource = endpointMetadataString(endpoint, "externalSource");
|
|
8211
|
-
const attachedTransport = endpointMetadataString(endpoint, "attachedTransport");
|
|
8212
|
-
return endpoint.metadata?.sessionBacked === true || source === "local-session" || externalSource === "local-session" || attachedTransport === "codex_app_server" || attachedTransport === "claude_stream_json";
|
|
8213
|
-
}
|
|
8214
|
-
function endpointAgentName(endpoint) {
|
|
8215
|
-
return endpointMetadataString(endpoint, "agentName") ?? endpointMetadataString(endpoint, "definitionId") ?? endpoint.agentId;
|
|
8216
|
-
}
|
|
8217
|
-
function endpointRuntimeInstanceId(endpoint) {
|
|
8218
|
-
return endpointMetadataString(endpoint, "runtimeInstanceId") ?? endpointMetadataString(endpoint, "runtimeSessionId") ?? endpoint.sessionId ?? `relay-${endpointAgentName(endpoint)}`;
|
|
8219
|
-
}
|
|
8220
|
-
function endpointCwd(endpoint) {
|
|
8221
|
-
return endpoint.cwd ?? endpoint.projectRoot ?? process.cwd();
|
|
8222
|
-
}
|
|
8223
|
-
function attachedLocalSessionSystemPrompt(endpoint) {
|
|
8224
|
-
const explicit = endpointMetadataString(endpoint, "systemPrompt");
|
|
8225
|
-
if (explicit) {
|
|
8226
|
-
return explicit;
|
|
8227
|
-
}
|
|
8228
|
-
return "Resume the existing session without changing its identity or prior context.";
|
|
8229
|
-
}
|
|
8230
|
-
function buildCodexEndpointSessionOptions(endpoint) {
|
|
8231
|
-
const agentName = endpointAgentName(endpoint);
|
|
8232
|
-
const threadId = endpointMetadataString(endpoint, "threadId") ?? endpointMetadataString(endpoint, "externalSessionId") ?? endpoint.sessionId ?? undefined;
|
|
8233
|
-
return {
|
|
8234
|
-
agentName,
|
|
8235
|
-
sessionId: endpointRuntimeInstanceId(endpoint),
|
|
8236
|
-
cwd: endpointCwd(endpoint),
|
|
8237
|
-
systemPrompt: attachedLocalSessionSystemPrompt(endpoint),
|
|
8238
|
-
runtimeDirectory: relayAgentRuntimeDirectory(agentName),
|
|
8239
|
-
logsDirectory: relayAgentLogsDirectory(agentName),
|
|
8240
|
-
launchArgs: [],
|
|
8241
|
-
threadId,
|
|
8242
|
-
requireExistingThread: Boolean(threadId)
|
|
8243
|
-
};
|
|
8244
|
-
}
|
|
8245
|
-
function buildClaudeEndpointSessionOptions(endpoint) {
|
|
8246
|
-
const agentName = endpointAgentName(endpoint);
|
|
8247
|
-
return {
|
|
8248
|
-
agentName,
|
|
8249
|
-
sessionId: endpointRuntimeInstanceId(endpoint),
|
|
8250
|
-
cwd: endpointCwd(endpoint),
|
|
8251
|
-
systemPrompt: attachedLocalSessionSystemPrompt(endpoint),
|
|
8252
|
-
runtimeDirectory: relayAgentRuntimeDirectory(agentName),
|
|
8253
|
-
logsDirectory: relayAgentLogsDirectory(agentName),
|
|
8254
|
-
launchArgs: []
|
|
8255
|
-
};
|
|
8256
|
-
}
|
|
8257
6725
|
function isLocalAgentRecordOnline(agentName, record) {
|
|
8258
6726
|
const normalizedRecord = normalizeLocalAgentRecord(agentName, record);
|
|
8259
6727
|
if (normalizedRecord.transport === "codex_app_server") {
|
|
@@ -8272,117 +6740,12 @@ function isLocalAgentSessionAlive(sessionName) {
|
|
|
8272
6740
|
return false;
|
|
8273
6741
|
}
|
|
8274
6742
|
}
|
|
8275
|
-
function isLocalAgentEndpointAlive(endpoint) {
|
|
8276
|
-
if (endpoint.transport === "pairing_bridge") {
|
|
8277
|
-
return endpoint.state !== "offline";
|
|
8278
|
-
}
|
|
8279
|
-
if (endpoint.transport === "codex_app_server") {
|
|
8280
|
-
return isCodexAppServerAgentAlive(buildCodexEndpointSessionOptions(endpoint));
|
|
8281
|
-
}
|
|
8282
|
-
if (endpoint.transport === "claude_stream_json") {
|
|
8283
|
-
return isClaudeStreamJsonAgentAlive(buildClaudeEndpointSessionOptions(endpoint));
|
|
8284
|
-
}
|
|
8285
|
-
const sessionId = endpoint.sessionId ?? (typeof endpoint.metadata?.tmuxSession === "string" ? String(endpoint.metadata.tmuxSession) : null);
|
|
8286
|
-
return sessionId ? isLocalAgentSessionAlive(sessionId) : false;
|
|
8287
|
-
}
|
|
8288
|
-
async function readBrokerMessagesSince(sinceSeconds) {
|
|
8289
|
-
const response = await fetch(new URL("/v1/snapshot", resolveBrokerUrl()));
|
|
8290
|
-
if (!response.ok) {
|
|
8291
|
-
throw new Error(`Broker snapshot failed: ${response.status} ${response.statusText}`);
|
|
8292
|
-
}
|
|
8293
|
-
const snapshot = await response.json();
|
|
8294
|
-
return Object.values(snapshot.messages).filter((message) => normalizeBrokerTimestamp(message.createdAt) >= sinceSeconds).sort((lhs, rhs) => normalizeBrokerTimestamp(lhs.createdAt) - normalizeBrokerTimestamp(rhs.createdAt));
|
|
8295
|
-
}
|
|
8296
6743
|
function buildLocalAgentSystemPrompt(agentName, projectName, projectPath, options = {}) {
|
|
8297
6744
|
return renderLocalAgentSystemPromptTemplate(buildLocalAgentSystemPromptTemplate(), buildLocalAgentTemplateContext(agentName, projectName, projectPath), options);
|
|
8298
6745
|
}
|
|
8299
6746
|
function buildLocalAgentInitialMessage(projectName, agentName) {
|
|
8300
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}"`;
|
|
8301
6748
|
}
|
|
8302
|
-
function buildLocalAgentDirectInvocationPrompt(agentName, invocation) {
|
|
8303
|
-
const contextLines = Object.entries(invocation.context ?? {}).map(([key, value]) => `- ${key}: ${String(value)}`);
|
|
8304
|
-
const collaborationContract = buildCollaborationContractPrompt(agentName);
|
|
8305
|
-
const collaborationContext = buildInvocationCollaborationContextPrompt(invocation);
|
|
8306
|
-
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.";
|
|
8307
|
-
return [
|
|
8308
|
-
`OpenScout invocation for ${agentName}.`,
|
|
8309
|
-
`Requester: ${invocation.requesterId}.`,
|
|
8310
|
-
`Action: ${invocation.action}.`,
|
|
8311
|
-
invocation.conversationId ? `Conversation: ${invocation.conversationId}.` : undefined,
|
|
8312
|
-
invocation.messageId ? `Message: ${invocation.messageId}.` : undefined,
|
|
8313
|
-
"",
|
|
8314
|
-
actionRules,
|
|
8315
|
-
collaborationContract,
|
|
8316
|
-
"Return only the reply that should be delivered back through the broker.",
|
|
8317
|
-
"",
|
|
8318
|
-
collaborationContext,
|
|
8319
|
-
contextLines.length > 0 ? `Context:
|
|
8320
|
-
${contextLines.join(`
|
|
8321
|
-
`)}` : undefined,
|
|
8322
|
-
"Task:",
|
|
8323
|
-
invocation.task
|
|
8324
|
-
].filter((value) => Boolean(value && value.length > 0)).join(`
|
|
8325
|
-
`);
|
|
8326
|
-
}
|
|
8327
|
-
function buildAttachedSessionInvocationPrompt(invocation) {
|
|
8328
|
-
const contextLines = Object.entries(invocation.context ?? {}).map(([key, value]) => `- ${key}: ${String(value)}`);
|
|
8329
|
-
return [
|
|
8330
|
-
`Scout message from ${invocation.requesterId}.`,
|
|
8331
|
-
invocation.conversationId ? `Conversation: ${invocation.conversationId}.` : undefined,
|
|
8332
|
-
invocation.messageId ? `Reply-To Message: ${invocation.messageId}.` : undefined,
|
|
8333
|
-
invocation.action !== "consult" ? `Requested action: ${invocation.action}.` : undefined,
|
|
8334
|
-
"Treat this as a direct message to the current session and reply normally as yourself in this session.",
|
|
8335
|
-
contextLines.length > 0 ? `Context:
|
|
8336
|
-
${contextLines.join(`
|
|
8337
|
-
`)}` : undefined,
|
|
8338
|
-
"",
|
|
8339
|
-
invocation.task
|
|
8340
|
-
].filter((value) => Boolean(value && value.length > 0)).join(`
|
|
8341
|
-
`);
|
|
8342
|
-
}
|
|
8343
|
-
function buildLocalAgentNudge(agentName, invocation, flightId) {
|
|
8344
|
-
const relayCommand = brokerRelayCommand();
|
|
8345
|
-
const parts = [
|
|
8346
|
-
`New broker ask from ${invocation.requesterId}.`,
|
|
8347
|
-
`Task: ${invocation.task}`,
|
|
8348
|
-
"Follow the OpenScout collaboration contract: answer directly if you can, otherwise make the next owner explicit and avoid broad wakeups."
|
|
8349
|
-
];
|
|
8350
|
-
if (invocation.context && Object.keys(invocation.context).length > 0) {
|
|
8351
|
-
parts.push(`Context: ${JSON.stringify(invocation.context)}`);
|
|
8352
|
-
}
|
|
8353
|
-
parts.push(`Read recent context if needed: ${relayCommand} read -n 20 --as ${agentName}.`);
|
|
8354
|
-
parts.push(`Reply with: ${relayCommand} send --as ${agentName} "[ask:${flightId}] @${invocation.requesterId} <your response>"`);
|
|
8355
|
-
return parts.join(" ");
|
|
8356
|
-
}
|
|
8357
|
-
function stripLocalAgentReplyMetadata(body, flightId, asker) {
|
|
8358
|
-
return body.replace(new RegExp(`\\[ask:${escapeRegExp(flightId)}\\]`, "g"), "").replace(new RegExp(`@${escapeRegExp(asker)}`, "g"), "").trim();
|
|
8359
|
-
}
|
|
8360
|
-
async function sendLocalAgentPrompt(agentName, record, prompt) {
|
|
8361
|
-
if (normalizeLocalAgentHarness(record.harness) === "codex") {
|
|
8362
|
-
const promptPipe = join8(relayAgentRuntimeDirectory(agentName), "prompt.pipe");
|
|
8363
|
-
await writeFile5(promptPipe, prompt.trim() + "\x00");
|
|
8364
|
-
return;
|
|
8365
|
-
}
|
|
8366
|
-
sendTmuxPrompt(record.tmuxSession, prompt);
|
|
8367
|
-
}
|
|
8368
|
-
function sendTmuxPrompt(sessionName, prompt) {
|
|
8369
|
-
const bufferName = `openscout-prompt-${randomUUID2()}`;
|
|
8370
|
-
try {
|
|
8371
|
-
execFileSync3("tmux", ["load-buffer", "-b", bufferName, "-"], {
|
|
8372
|
-
stdio: "pipe",
|
|
8373
|
-
input: prompt
|
|
8374
|
-
});
|
|
8375
|
-
execFileSync3("tmux", ["paste-buffer", "-d", "-b", bufferName, "-t", sessionName], {
|
|
8376
|
-
stdio: "pipe"
|
|
8377
|
-
});
|
|
8378
|
-
execFileSync3("tmux", ["send-keys", "-t", sessionName, "Enter"], { stdio: "pipe" });
|
|
8379
|
-
} catch (error) {
|
|
8380
|
-
try {
|
|
8381
|
-
execFileSync3("tmux", ["delete-buffer", "-b", bufferName], { stdio: "pipe" });
|
|
8382
|
-
} catch {}
|
|
8383
|
-
throw error;
|
|
8384
|
-
}
|
|
8385
|
-
}
|
|
8386
6749
|
function shellQuoteArguments(args) {
|
|
8387
6750
|
return args.map((arg) => JSON.stringify(arg)).join(" ");
|
|
8388
6751
|
}
|
|
@@ -9078,110 +7441,6 @@ async function ensureLocalAgentBindingOnline(agentId, nodeId, options = {}) {
|
|
|
9078
7441
|
const onlineRecord = await ensureLocalAgentOnline(agentId, recordForHarness(localAgentRecordFromRelayAgentOverride(agentId, override), options.harness));
|
|
9079
7442
|
return buildLocalAgentBinding(agentId, onlineRecord, isLocalAgentRecordOnline(agentId, onlineRecord), nodeId, "relay-agent-registry");
|
|
9080
7443
|
}
|
|
9081
|
-
async function invokeLocalAgentEndpoint(endpoint, invocation) {
|
|
9082
|
-
const agentRuntimeId = endpoint.agentId;
|
|
9083
|
-
const definitionId = String(endpoint.metadata?.definitionId ?? endpoint.metadata?.agentName ?? endpoint.agentId);
|
|
9084
|
-
const prompt = endpointInvocationPrompt(endpoint, definitionId, invocation);
|
|
9085
|
-
const registry = await readLocalAgentRegistry();
|
|
9086
|
-
const existing = registry[agentRuntimeId];
|
|
9087
|
-
if (!existing && endpoint.transport === "codex_app_server") {
|
|
9088
|
-
await ensureLocalSessionEndpointOnline(endpoint);
|
|
9089
|
-
const invoke = isSessionBackedEndpoint(endpoint) ? sendCodexAppServerAgent : invokeCodexAppServerAgent;
|
|
9090
|
-
const result = await invoke({
|
|
9091
|
-
...buildCodexEndpointSessionOptions(endpoint),
|
|
9092
|
-
prompt,
|
|
9093
|
-
timeoutMs: invocation.timeoutMs
|
|
9094
|
-
});
|
|
9095
|
-
return {
|
|
9096
|
-
output: result.output
|
|
9097
|
-
};
|
|
9098
|
-
}
|
|
9099
|
-
if (!existing && endpoint.transport === "claude_stream_json") {
|
|
9100
|
-
await ensureLocalSessionEndpointOnline(endpoint);
|
|
9101
|
-
const result = await invokeClaudeStreamJsonAgent({
|
|
9102
|
-
...buildClaudeEndpointSessionOptions(endpoint),
|
|
9103
|
-
prompt,
|
|
9104
|
-
timeoutMs: invocation.timeoutMs
|
|
9105
|
-
});
|
|
9106
|
-
return {
|
|
9107
|
-
output: result.output
|
|
9108
|
-
};
|
|
9109
|
-
}
|
|
9110
|
-
const projectRoot = endpoint.projectRoot ?? endpoint.cwd;
|
|
9111
|
-
const requestedHarness = invocation.execution?.harness;
|
|
9112
|
-
const record = existing ?? (projectRoot ? {
|
|
9113
|
-
definitionId,
|
|
9114
|
-
project: basename3(projectRoot),
|
|
9115
|
-
projectRoot,
|
|
9116
|
-
tmuxSession: String(endpoint.metadata?.tmuxSession ?? `relay-${agentRuntimeId}`),
|
|
9117
|
-
cwd: projectRoot,
|
|
9118
|
-
startedAt: nowSeconds2(),
|
|
9119
|
-
harness: normalizeLocalAgentHarness(typeof endpoint.harness === "string" ? endpoint.harness : undefined),
|
|
9120
|
-
defaultHarness: normalizeLocalAgentHarness(typeof endpoint.harness === "string" ? endpoint.harness : undefined),
|
|
9121
|
-
harnessProfiles: {
|
|
9122
|
-
[normalizeManagedHarness2(typeof endpoint.harness === "string" ? endpoint.harness : undefined, "claude")]: {
|
|
9123
|
-
cwd: projectRoot,
|
|
9124
|
-
sessionId: String(endpoint.sessionId ?? endpoint.metadata?.runtimeInstanceId ?? endpoint.metadata?.runtimeSessionId ?? `relay-${agentRuntimeId}`),
|
|
9125
|
-
transport: normalizeLocalAgentTransport(typeof endpoint.transport === "string" ? endpoint.transport : undefined, normalizeLocalAgentHarness(typeof endpoint.harness === "string" ? endpoint.harness : undefined)),
|
|
9126
|
-
launchArgs: []
|
|
9127
|
-
}
|
|
9128
|
-
},
|
|
9129
|
-
transport: normalizeLocalAgentTransport(typeof endpoint.transport === "string" ? endpoint.transport : undefined, normalizeLocalAgentHarness(typeof endpoint.harness === "string" ? endpoint.harness : undefined)),
|
|
9130
|
-
capabilities: [...DEFAULT_LOCAL_AGENT_CAPABILITIES],
|
|
9131
|
-
launchArgs: []
|
|
9132
|
-
} : null);
|
|
9133
|
-
if (!record) {
|
|
9134
|
-
throw new Error(`Agent ${agentRuntimeId} is not registered and has no project root.`);
|
|
9135
|
-
}
|
|
9136
|
-
const selectedRecord = recordForHarness(record, requestedHarness);
|
|
9137
|
-
const onlineRecord = await ensureLocalAgentOnline(agentRuntimeId, selectedRecord);
|
|
9138
|
-
if (onlineRecord.transport === "codex_app_server") {
|
|
9139
|
-
const result = await invokeCodexAppServerAgent({
|
|
9140
|
-
...buildCodexAgentSessionOptions(agentRuntimeId, onlineRecord, renderLocalAgentSystemPromptTemplate(onlineRecord.systemPrompt || buildLocalAgentSystemPromptTemplate(), buildLocalAgentTemplateContext(definitionId, onlineRecord.project, onlineRecord.cwd), { transport: "codex_app_server" })),
|
|
9141
|
-
prompt,
|
|
9142
|
-
timeoutMs: invocation.timeoutMs
|
|
9143
|
-
});
|
|
9144
|
-
return {
|
|
9145
|
-
output: result.output
|
|
9146
|
-
};
|
|
9147
|
-
}
|
|
9148
|
-
if (onlineRecord.transport === "claude_stream_json") {
|
|
9149
|
-
const result = await invokeClaudeStreamJsonAgent({
|
|
9150
|
-
...buildClaudeAgentSessionOptions(agentRuntimeId, onlineRecord, renderLocalAgentSystemPromptTemplate(onlineRecord.systemPrompt || buildLocalAgentSystemPromptTemplate(), buildLocalAgentTemplateContext(definitionId, onlineRecord.project, onlineRecord.cwd), { transport: "claude_stream_json" })),
|
|
9151
|
-
prompt,
|
|
9152
|
-
timeoutMs: invocation.timeoutMs
|
|
9153
|
-
});
|
|
9154
|
-
return {
|
|
9155
|
-
output: result.output
|
|
9156
|
-
};
|
|
9157
|
-
}
|
|
9158
|
-
const flightId = createLocalAgentFlightId();
|
|
9159
|
-
const askedAt = nowSeconds2();
|
|
9160
|
-
const timeoutSeconds = invocation.timeoutMs ? Math.max(30, Math.floor(invocation.timeoutMs / 1000)) : 300;
|
|
9161
|
-
await sendLocalAgentPrompt(agentRuntimeId, onlineRecord, buildLocalAgentNudge(definitionId, invocation, flightId));
|
|
9162
|
-
const deadline = Date.now() + timeoutSeconds * 1000;
|
|
9163
|
-
while (Date.now() <= deadline) {
|
|
9164
|
-
const messages2 = await readBrokerMessagesSince(askedAt - 1);
|
|
9165
|
-
for (let index = messages2.length - 1;index >= 0; index -= 1) {
|
|
9166
|
-
const message = messages2[index];
|
|
9167
|
-
if (message.actorId !== agentRuntimeId)
|
|
9168
|
-
continue;
|
|
9169
|
-
if (!message.body.includes(`[ask:${flightId}]`))
|
|
9170
|
-
continue;
|
|
9171
|
-
return {
|
|
9172
|
-
output: stripLocalAgentReplyMetadata(message.body, flightId, invocation.requesterId)
|
|
9173
|
-
};
|
|
9174
|
-
}
|
|
9175
|
-
await sleep2(500);
|
|
9176
|
-
}
|
|
9177
|
-
throw new Error(`Timed out after ${timeoutSeconds}s waiting for ${agentRuntimeId}.`);
|
|
9178
|
-
}
|
|
9179
|
-
function shouldDisableGeneratedCodexEndpoint(endpoint) {
|
|
9180
|
-
if (endpoint.transport !== "codex_exec") {
|
|
9181
|
-
return false;
|
|
9182
|
-
}
|
|
9183
|
-
return endpoint.metadata?.source === "scout-app";
|
|
9184
|
-
}
|
|
9185
7444
|
var MODULE_DIRECTORY, OPENSCOUT_REPO_ROOT, DEFAULT_LOCAL_AGENT_CAPABILITIES, DEFAULT_LOCAL_AGENT_HARNESS = "claude", SUPPORTED_LOCAL_AGENT_HARNESSES;
|
|
9186
7445
|
var init_local_agents = __esm(async () => {
|
|
9187
7446
|
init_src();
|
|
@@ -9279,19 +7538,41 @@ function resolveScoutAgentName(agentName) {
|
|
|
9279
7538
|
}
|
|
9280
7539
|
return resolveOperatorName();
|
|
9281
7540
|
}
|
|
9282
|
-
|
|
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) {
|
|
9283
7565
|
if (agentName?.trim()) {
|
|
9284
7566
|
return agentName.trim();
|
|
9285
7567
|
}
|
|
9286
|
-
if (
|
|
9287
|
-
return
|
|
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();
|
|
9288
7574
|
}
|
|
9289
|
-
|
|
9290
|
-
const { resolveLocalAgentByName: resolveLocalAgentByName2 } = await init_local_agents().then(() => exports_local_agents);
|
|
9291
|
-
const projectRoot = await findNearestProjectRoot2(currentDirectory) ?? currentDirectory;
|
|
9292
|
-
const projectName = basename4(projectRoot);
|
|
9293
|
-
const agent = await resolveLocalAgentByName2(projectName);
|
|
9294
|
-
return agent?.agentId ?? projectName;
|
|
7575
|
+
return inferSenderIdForProjectRoot(projectRoot);
|
|
9295
7576
|
}
|
|
9296
7577
|
function parseScoutHarness(value) {
|
|
9297
7578
|
const trimmed = value?.trim();
|
|
@@ -9865,14 +8146,17 @@ async function sendScoutMessage(input) {
|
|
|
9865
8146
|
const senderId = await resolveConversationActorId(broker.baseUrl, broker.snapshot, broker.node.id, input.senderId, currentDirectory);
|
|
9866
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));
|
|
9867
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
|
+
}
|
|
9868
8153
|
let conversation;
|
|
9869
8154
|
if (validTargets.length === 1 && !input.channel) {
|
|
9870
8155
|
const dm = await ensureBrokerDirectConversationBetween(broker.baseUrl, broker.snapshot, broker.node.id, senderId, validTargets[0]);
|
|
9871
8156
|
conversation = dm.conversation;
|
|
9872
8157
|
} else {
|
|
9873
|
-
conversation = await ensureBrokerConversation(broker.baseUrl, broker.snapshot, broker.node.id, input.channel, senderId,
|
|
8158
|
+
conversation = await ensureBrokerConversation(broker.baseUrl, broker.snapshot, broker.node.id, input.channel, senderId, validTargets);
|
|
9874
8159
|
}
|
|
9875
|
-
const unresolvedTargets = mentionResolution.resolved.filter((target) => !validTargets.includes(target.agentId)).map((target) => target.label).concat(mentionResolution.unresolved).concat(mentionResolution.ambiguous.map((entry) => entry.label));
|
|
9876
8160
|
const messageId = `m-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;
|
|
9877
8161
|
const speechText = input.shouldSpeak ? stripScoutAgentSelectorLabels(input.body) : "";
|
|
9878
8162
|
const returnAddress = buildScoutReturnAddress(broker.snapshot, senderId, {
|
|
@@ -9899,27 +8183,6 @@ async function sendScoutMessage(input) {
|
|
|
9899
8183
|
returnAddress
|
|
9900
8184
|
}
|
|
9901
8185
|
});
|
|
9902
|
-
for (const targetAgentId of validTargets) {
|
|
9903
|
-
await brokerPostJson(broker.baseUrl, scoutBrokerPaths.v1.invocations, {
|
|
9904
|
-
id: `inv-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`,
|
|
9905
|
-
requesterId: senderId,
|
|
9906
|
-
requesterNodeId: broker.node.id,
|
|
9907
|
-
targetAgentId,
|
|
9908
|
-
action: "consult",
|
|
9909
|
-
task: input.body,
|
|
9910
|
-
conversationId: conversation.id,
|
|
9911
|
-
messageId,
|
|
9912
|
-
execution: input.executionHarness ? { harness: input.executionHarness } : undefined,
|
|
9913
|
-
ensureAwake: true,
|
|
9914
|
-
stream: false,
|
|
9915
|
-
createdAt: Date.now(),
|
|
9916
|
-
metadata: {
|
|
9917
|
-
source: "scout-cli",
|
|
9918
|
-
relayChannel: input.channel ?? "shared",
|
|
9919
|
-
returnAddress
|
|
9920
|
-
}
|
|
9921
|
-
});
|
|
9922
|
-
}
|
|
9923
8186
|
return { usedBroker: true, invokedTargets: validTargets, unresolvedTargets };
|
|
9924
8187
|
}
|
|
9925
8188
|
async function openScoutPeerSession(input) {
|
|
@@ -10204,7 +8467,7 @@ async function watchScoutMessages(options) {
|
|
|
10204
8467
|
return;
|
|
10205
8468
|
}
|
|
10206
8469
|
const message = event.payload?.message;
|
|
10207
|
-
if (!message || message.conversationId !== conversationId
|
|
8470
|
+
if (!message || message.conversationId !== conversationId)
|
|
10208
8471
|
return;
|
|
10209
8472
|
options.onMessage(message);
|
|
10210
8473
|
};
|
|
@@ -10501,13 +8764,15 @@ async function runAskCommand(context, args) {
|
|
|
10501
8764
|
await runAskWithOptions(context, options);
|
|
10502
8765
|
}
|
|
10503
8766
|
async function runAskWithOptions(context, options) {
|
|
8767
|
+
const currentDirectory = options.currentDirectory ?? defaultScoutContextDirectory(context);
|
|
8768
|
+
const senderId = await resolveScoutSenderId(options.agentName, currentDirectory, context.env);
|
|
10504
8769
|
const result = await askScoutQuestion({
|
|
10505
|
-
senderId
|
|
8770
|
+
senderId,
|
|
10506
8771
|
targetLabel: options.targetLabel,
|
|
10507
8772
|
body: options.message,
|
|
10508
8773
|
channel: options.channel,
|
|
10509
8774
|
executionHarness: parseScoutHarness(options.harness),
|
|
10510
|
-
currentDirectory
|
|
8775
|
+
currentDirectory
|
|
10511
8776
|
});
|
|
10512
8777
|
if (!result.usedBroker) {
|
|
10513
8778
|
throw new Error("broker is not reachable");
|
|
@@ -10597,8 +8862,116 @@ function renderScoutBroadcastResult(result) {
|
|
|
10597
8862
|
return lines.join(`
|
|
10598
8863
|
`);
|
|
10599
8864
|
}
|
|
8865
|
+
function renderScoutActivityKind(kind) {
|
|
8866
|
+
switch (kind) {
|
|
8867
|
+
case "ask_opened":
|
|
8868
|
+
return "asked";
|
|
8869
|
+
case "ask_working":
|
|
8870
|
+
return "working";
|
|
8871
|
+
case "ask_replied":
|
|
8872
|
+
return "replied";
|
|
8873
|
+
case "ask_failed":
|
|
8874
|
+
return "failed";
|
|
8875
|
+
case "handoff_sent":
|
|
8876
|
+
return "handoff";
|
|
8877
|
+
case "agent_message":
|
|
8878
|
+
return "agent";
|
|
8879
|
+
case "status_message":
|
|
8880
|
+
return "status";
|
|
8881
|
+
case "invocation_recorded":
|
|
8882
|
+
return "invoke";
|
|
8883
|
+
case "flight_updated":
|
|
8884
|
+
return "flight";
|
|
8885
|
+
case "collaboration_event":
|
|
8886
|
+
return "collab";
|
|
8887
|
+
case "message_posted":
|
|
8888
|
+
default:
|
|
8889
|
+
return "message";
|
|
8890
|
+
}
|
|
8891
|
+
}
|
|
8892
|
+
function renderScoutActivityParticipants(item) {
|
|
8893
|
+
const actor = item.actorId?.trim();
|
|
8894
|
+
const counterpart = item.counterpartId?.trim();
|
|
8895
|
+
if (actor && counterpart && actor !== counterpart) {
|
|
8896
|
+
return `${actor} -> ${counterpart}`;
|
|
8897
|
+
}
|
|
8898
|
+
return actor || counterpart || item.agentId?.trim() || null;
|
|
8899
|
+
}
|
|
8900
|
+
function renderScoutActivityItem(item) {
|
|
8901
|
+
const timestamp = normalizeUnixTimestamp2(item.ts) ?? Math.floor(Date.now() / 1000);
|
|
8902
|
+
const label = renderScoutActivityKind(item.kind).padEnd(7, " ");
|
|
8903
|
+
const participants = renderScoutActivityParticipants(item);
|
|
8904
|
+
const title = item.title?.trim() || item.summary?.trim() || item.kind;
|
|
8905
|
+
const summary = item.summary?.trim();
|
|
8906
|
+
const detail = summary && summary !== title ? summary : null;
|
|
8907
|
+
return [
|
|
8908
|
+
formatScoutTimestamp(timestamp),
|
|
8909
|
+
label,
|
|
8910
|
+
participants,
|
|
8911
|
+
title,
|
|
8912
|
+
detail ? `(${detail})` : null
|
|
8913
|
+
].filter(Boolean).join(" ");
|
|
8914
|
+
}
|
|
8915
|
+
function renderScoutActivityList(items) {
|
|
8916
|
+
if (items.length === 0) {
|
|
8917
|
+
return "No Scout activity yet.";
|
|
8918
|
+
}
|
|
8919
|
+
return items.map(renderScoutActivityItem).join(`
|
|
8920
|
+
`);
|
|
8921
|
+
}
|
|
10600
8922
|
var init_broker = () => {};
|
|
10601
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
|
+
|
|
10602
8975
|
// ../../apps/desktop/src/cli/commands/broadcast.ts
|
|
10603
8976
|
var exports_broadcast = {};
|
|
10604
8977
|
__export(exports_broadcast, {
|
|
@@ -10606,15 +8979,20 @@ __export(exports_broadcast, {
|
|
|
10606
8979
|
});
|
|
10607
8980
|
async function runBroadcastCommand(context, args) {
|
|
10608
8981
|
const options = parseSendCommandOptions(args, defaultScoutContextDirectory(context));
|
|
8982
|
+
const currentDirectory = options.currentDirectory ?? defaultScoutContextDirectory(context);
|
|
8983
|
+
const senderId = await resolveScoutSenderId(options.agentName, currentDirectory, context.env);
|
|
10609
8984
|
const result = await sendScoutMessage({
|
|
10610
|
-
senderId
|
|
8985
|
+
senderId,
|
|
10611
8986
|
body: `@all ${options.message}`,
|
|
10612
8987
|
executionHarness: parseScoutHarness(options.harness),
|
|
10613
|
-
currentDirectory
|
|
8988
|
+
currentDirectory
|
|
10614
8989
|
});
|
|
10615
8990
|
if (!result.usedBroker) {
|
|
10616
8991
|
throw new Error("broker is not reachable");
|
|
10617
8992
|
}
|
|
8993
|
+
if (result.unresolvedTargets.length > 0) {
|
|
8994
|
+
throw new Error(formatScoutSendRoutingError(result.unresolvedTargets));
|
|
8995
|
+
}
|
|
10618
8996
|
context.output.writeValue({
|
|
10619
8997
|
message: options.message,
|
|
10620
8998
|
invokedTargets: result.invokedTargets,
|
|
@@ -10625,7 +9003,10 @@ var init_broadcast = __esm(async () => {
|
|
|
10625
9003
|
init_context();
|
|
10626
9004
|
init_options();
|
|
10627
9005
|
init_broker();
|
|
10628
|
-
await
|
|
9006
|
+
await __promiseAll([
|
|
9007
|
+
init_service(),
|
|
9008
|
+
init_send()
|
|
9009
|
+
]);
|
|
10629
9010
|
});
|
|
10630
9011
|
|
|
10631
9012
|
// ../runtime/src/relay-agent-cards.ts
|
|
@@ -11718,7 +10099,7 @@ function resolveScoutBinPath(appRoot) {
|
|
|
11718
10099
|
}
|
|
11719
10100
|
return candidates[candidates.length - 1];
|
|
11720
10101
|
}
|
|
11721
|
-
function loadScoutEnvReport(context, currentDirectory) {
|
|
10102
|
+
async function loadScoutEnvReport(context, currentDirectory) {
|
|
11722
10103
|
const appRoot = resolveScoutAppRoot({
|
|
11723
10104
|
currentDirectory,
|
|
11724
10105
|
env: context.env
|
|
@@ -11736,6 +10117,8 @@ function loadScoutEnvReport(context, currentDirectory) {
|
|
|
11736
10117
|
const binPath = resolveScoutBinPath(appRoot);
|
|
11737
10118
|
const scoutPath = resolveCommandOnPath("scout", context.env);
|
|
11738
10119
|
const fallbackCommand = `bun ${binPath}`;
|
|
10120
|
+
const resolvedId = await resolveScoutSenderId(null, currentDirectory, context.env);
|
|
10121
|
+
const projectRoot = await findNearestProjectRoot(currentDirectory);
|
|
11739
10122
|
return {
|
|
11740
10123
|
executable: {
|
|
11741
10124
|
command: scoutPath ? "scout" : fallbackCommand,
|
|
@@ -11743,8 +10126,9 @@ function loadScoutEnvReport(context, currentDirectory) {
|
|
|
11743
10126
|
scoutPath
|
|
11744
10127
|
},
|
|
11745
10128
|
agent: {
|
|
11746
|
-
resolvedId
|
|
11747
|
-
envAgent: context.env.OPENSCOUT_AGENT?.trim() || null
|
|
10129
|
+
resolvedId,
|
|
10130
|
+
envAgent: context.env.OPENSCOUT_AGENT?.trim() || null,
|
|
10131
|
+
projectRoot
|
|
11748
10132
|
},
|
|
11749
10133
|
context: {
|
|
11750
10134
|
cwd: context.cwd,
|
|
@@ -11771,16 +10155,306 @@ function renderScoutEnvReport(report) {
|
|
|
11771
10155
|
}
|
|
11772
10156
|
async function runEnvCommand(context, args) {
|
|
11773
10157
|
const options = parseContextRootCommandOptions("env", args, defaultScoutContextDirectory(context));
|
|
11774
|
-
const report = loadScoutEnvReport(context, options.currentDirectory);
|
|
10158
|
+
const report = await loadScoutEnvReport(context, options.currentDirectory);
|
|
11775
10159
|
context.output.writeValue(report, renderScoutEnvReport);
|
|
11776
10160
|
}
|
|
11777
10161
|
var init_env = __esm(async () => {
|
|
10162
|
+
init_setup();
|
|
11778
10163
|
init_context();
|
|
11779
10164
|
init_options();
|
|
11780
10165
|
init_paths2();
|
|
11781
10166
|
await init_service();
|
|
11782
10167
|
});
|
|
11783
10168
|
|
|
10169
|
+
// ../../apps/desktop/src/cli/commands/latest.ts
|
|
10170
|
+
var exports_latest = {};
|
|
10171
|
+
__export(exports_latest, {
|
|
10172
|
+
runLatestCommand: () => runLatestCommand
|
|
10173
|
+
});
|
|
10174
|
+
async function runLatestCommand(context, args) {
|
|
10175
|
+
const options = parseLatestCommandOptions(args, defaultScoutContextDirectory(context));
|
|
10176
|
+
const items = await loadScoutActivityItems({
|
|
10177
|
+
agentId: options.agentId,
|
|
10178
|
+
actorId: options.actorId,
|
|
10179
|
+
conversationId: options.conversationId,
|
|
10180
|
+
limit: options.limit
|
|
10181
|
+
});
|
|
10182
|
+
context.output.writeValue(items, renderScoutActivityList);
|
|
10183
|
+
}
|
|
10184
|
+
var init_latest = __esm(async () => {
|
|
10185
|
+
init_context();
|
|
10186
|
+
init_options();
|
|
10187
|
+
init_broker();
|
|
10188
|
+
await init_service();
|
|
10189
|
+
});
|
|
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
|
+
|
|
11784
10458
|
// ../runtime/src/tailscale.ts
|
|
11785
10459
|
import { readFile as readFile8 } from "fs/promises";
|
|
11786
10460
|
import { execFile } from "child_process";
|
|
@@ -12243,11 +10917,11 @@ var init_mesh = __esm(async () => {
|
|
|
12243
10917
|
});
|
|
12244
10918
|
|
|
12245
10919
|
// ../../apps/desktop/src/core/pairing/runtime/config.ts
|
|
12246
|
-
import { existsSync as
|
|
12247
|
-
import { homedir as
|
|
10920
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
|
|
10921
|
+
import { homedir as homedir8 } from "os";
|
|
12248
10922
|
import path from "path";
|
|
12249
10923
|
function pairingPaths() {
|
|
12250
|
-
const rootDir = path.join(
|
|
10924
|
+
const rootDir = path.join(homedir8(), ".scout/pairing");
|
|
12251
10925
|
return {
|
|
12252
10926
|
rootDir,
|
|
12253
10927
|
configPath: path.join(rootDir, "config.json"),
|
|
@@ -12260,7 +10934,7 @@ function pairingPaths() {
|
|
|
12260
10934
|
}
|
|
12261
10935
|
function loadPairingConfig() {
|
|
12262
10936
|
const { configPath } = pairingPaths();
|
|
12263
|
-
if (!
|
|
10937
|
+
if (!existsSync11(configPath)) {
|
|
12264
10938
|
return {};
|
|
12265
10939
|
}
|
|
12266
10940
|
try {
|
|
@@ -14347,11 +13021,11 @@ var init_noise = __esm(() => {
|
|
|
14347
13021
|
});
|
|
14348
13022
|
|
|
14349
13023
|
// ../../apps/desktop/src/core/pairing/runtime/security/identity.ts
|
|
14350
|
-
import { existsSync as
|
|
14351
|
-
import { join as
|
|
14352
|
-
import { homedir as
|
|
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";
|
|
14353
13027
|
function loadOrCreateIdentity() {
|
|
14354
|
-
if (
|
|
13028
|
+
if (existsSync12(IDENTITY_FILE)) {
|
|
14355
13029
|
return loadIdentity();
|
|
14356
13030
|
}
|
|
14357
13031
|
return createAndSaveIdentity();
|
|
@@ -14375,7 +13049,7 @@ function createAndSaveIdentity() {
|
|
|
14375
13049
|
return keyPair;
|
|
14376
13050
|
}
|
|
14377
13051
|
function loadTrustedPeers() {
|
|
14378
|
-
if (!
|
|
13052
|
+
if (!existsSync12(TRUSTED_PEERS_FILE))
|
|
14379
13053
|
return new Map;
|
|
14380
13054
|
const data = JSON.parse(readFileSync7(TRUSTED_PEERS_FILE, "utf8"));
|
|
14381
13055
|
return new Map(data.map((p) => [p.publicKey, p]));
|
|
@@ -14411,9 +13085,9 @@ function hexToBytes2(hex) {
|
|
|
14411
13085
|
var PAIRING_DIR, IDENTITY_FILE, TRUSTED_PEERS_FILE, QR_VERSION = 1, QR_EXPIRY_MS;
|
|
14412
13086
|
var init_identity = __esm(() => {
|
|
14413
13087
|
init_noise();
|
|
14414
|
-
PAIRING_DIR =
|
|
14415
|
-
IDENTITY_FILE =
|
|
14416
|
-
TRUSTED_PEERS_FILE =
|
|
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");
|
|
14417
13091
|
QR_EXPIRY_MS = 5 * 60 * 1000;
|
|
14418
13092
|
});
|
|
14419
13093
|
|
|
@@ -14558,10 +13232,10 @@ var init_security2 = __esm(() => {
|
|
|
14558
13232
|
});
|
|
14559
13233
|
|
|
14560
13234
|
// ../../apps/desktop/src/core/pairing/runtime/runtime-state.ts
|
|
14561
|
-
import { existsSync as
|
|
13235
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync6, readFileSync as readFileSync8, renameSync, unlinkSync, writeFileSync as writeFileSync6 } from "fs";
|
|
14562
13236
|
function readPairingRuntimeSnapshot() {
|
|
14563
13237
|
const { runtimeStatePath } = pairingPaths();
|
|
14564
|
-
if (!
|
|
13238
|
+
if (!existsSync13(runtimeStatePath)) {
|
|
14565
13239
|
return null;
|
|
14566
13240
|
}
|
|
14567
13241
|
try {
|
|
@@ -15090,17 +13764,17 @@ var init_registry = __esm(() => {
|
|
|
15090
13764
|
});
|
|
15091
13765
|
|
|
15092
13766
|
// ../agent-sessions/src/adapters/claude-code.ts
|
|
15093
|
-
import { existsSync as
|
|
15094
|
-
import { homedir as
|
|
15095
|
-
import { join as
|
|
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";
|
|
15096
13770
|
function resolveClaudeResumeContext(config) {
|
|
15097
13771
|
const rawResumeId = config.options?.["resume"];
|
|
15098
13772
|
const resumeId = typeof rawResumeId === "string" ? rawResumeId.trim().replace(/\.jsonl$/u, "") : "";
|
|
15099
13773
|
if (!resumeId) {
|
|
15100
13774
|
return null;
|
|
15101
13775
|
}
|
|
15102
|
-
const projectsRoot =
|
|
15103
|
-
if (!
|
|
13776
|
+
const projectsRoot = join17(homedir10(), ".claude", "projects");
|
|
13777
|
+
if (!existsSync14(projectsRoot)) {
|
|
15104
13778
|
return null;
|
|
15105
13779
|
}
|
|
15106
13780
|
let projectSlugs;
|
|
@@ -15110,8 +13784,8 @@ function resolveClaudeResumeContext(config) {
|
|
|
15110
13784
|
return null;
|
|
15111
13785
|
}
|
|
15112
13786
|
for (const slug of projectSlugs) {
|
|
15113
|
-
const sessionPath =
|
|
15114
|
-
if (!
|
|
13787
|
+
const sessionPath = join17(projectsRoot, slug, `${resumeId}.jsonl`);
|
|
13788
|
+
if (!existsSync14(sessionPath)) {
|
|
15115
13789
|
continue;
|
|
15116
13790
|
}
|
|
15117
13791
|
const cwd = decodeClaudeProjectsSlug2(slug);
|
|
@@ -15550,11 +14224,11 @@ Referenced files: ${prompt.files.join(", ")}` });
|
|
|
15550
14224
|
});
|
|
15551
14225
|
}
|
|
15552
14226
|
answerQuestion(answer) {
|
|
15553
|
-
const
|
|
15554
|
-
if (!
|
|
14227
|
+
const resolve9 = this.pendingAnswers.get(answer.blockId);
|
|
14228
|
+
if (!resolve9)
|
|
15555
14229
|
return;
|
|
15556
14230
|
this.pendingAnswers.delete(answer.blockId);
|
|
15557
|
-
|
|
14231
|
+
resolve9(answer.answer);
|
|
15558
14232
|
const turn = this.currentTurn;
|
|
15559
14233
|
if (turn) {
|
|
15560
14234
|
this.emit("event", {
|
|
@@ -15568,8 +14242,8 @@ Referenced files: ${prompt.files.join(", ")}` });
|
|
|
15568
14242
|
}
|
|
15569
14243
|
}
|
|
15570
14244
|
async awaitAndSendAnswer(blockId, toolCallId) {
|
|
15571
|
-
const answer = await new Promise((
|
|
15572
|
-
this.pendingAnswers.set(blockId,
|
|
14245
|
+
const answer = await new Promise((resolve9) => {
|
|
14246
|
+
this.pendingAnswers.set(blockId, resolve9);
|
|
15573
14247
|
});
|
|
15574
14248
|
if (!this.process?.stdin || typeof this.process.stdin === "number")
|
|
15575
14249
|
return;
|
|
@@ -15654,8 +14328,8 @@ Referenced files: ${prompt.files.join(", ")}` });
|
|
|
15654
14328
|
// ../agent-sessions/src/adapters/codex.ts
|
|
15655
14329
|
import { spawn as spawn4 } from "child_process";
|
|
15656
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";
|
|
15657
|
-
import { delimiter as delimiter2, join as
|
|
15658
|
-
import { homedir as
|
|
14331
|
+
import { delimiter as delimiter2, join as join18 } from "path";
|
|
14332
|
+
import { homedir as homedir11 } from "os";
|
|
15659
14333
|
function parseJsonLine2(line) {
|
|
15660
14334
|
try {
|
|
15661
14335
|
return JSON.parse(line);
|
|
@@ -15805,7 +14479,7 @@ async function resolveCodexExecutable2() {
|
|
|
15805
14479
|
"/usr/local/bin"
|
|
15806
14480
|
].filter(Boolean);
|
|
15807
14481
|
for (const directory of [...pathEntries, ...commonDirectories]) {
|
|
15808
|
-
const candidate =
|
|
14482
|
+
const candidate = join18(directory, "codex");
|
|
15809
14483
|
if (await isExecutable2(candidate)) {
|
|
15810
14484
|
return candidate;
|
|
15811
14485
|
}
|
|
@@ -15909,7 +14583,7 @@ var init_codex = __esm(() => {
|
|
|
15909
14583
|
this.pendingRequests.clear();
|
|
15910
14584
|
if (child && child.exitCode === null && !child.killed) {
|
|
15911
14585
|
child.kill("SIGTERM");
|
|
15912
|
-
await new Promise((
|
|
14586
|
+
await new Promise((resolve9) => setTimeout(resolve9, 250));
|
|
15913
14587
|
if (child.exitCode === null && !child.killed) {
|
|
15914
14588
|
child.kill("SIGKILL");
|
|
15915
14589
|
}
|
|
@@ -15918,7 +14592,7 @@ var init_codex = __esm(() => {
|
|
|
15918
14592
|
await this.persistState();
|
|
15919
14593
|
}
|
|
15920
14594
|
get codexOptions() {
|
|
15921
|
-
const runtimeRoot =
|
|
14595
|
+
const runtimeRoot = join18(homedir11(), ".scout/pairing", "codex", this.session.id);
|
|
15922
14596
|
const configuredThreadId = this.config.options?.["threadId"];
|
|
15923
14597
|
const requireExistingThread = this.config.options?.["requireExistingThread"];
|
|
15924
14598
|
const rawLaunchArgs = this.config.options?.["launchArgs"];
|
|
@@ -15928,8 +14602,8 @@ var init_codex = __esm(() => {
|
|
|
15928
14602
|
sessionId: this.session.id,
|
|
15929
14603
|
cwd: this.config.cwd ?? process.cwd(),
|
|
15930
14604
|
systemPrompt: this.systemPrompt,
|
|
15931
|
-
runtimeDirectory:
|
|
15932
|
-
logsDirectory:
|
|
14605
|
+
runtimeDirectory: join18(runtimeRoot, "runtime"),
|
|
14606
|
+
logsDirectory: join18(runtimeRoot, "logs"),
|
|
15933
14607
|
launchArgs,
|
|
15934
14608
|
threadId: typeof configuredThreadId === "string" && configuredThreadId.trim().length > 0 ? configuredThreadId.trim() : undefined,
|
|
15935
14609
|
requireExistingThread: requireExistingThread ?? Boolean(configuredThreadId)
|
|
@@ -15940,16 +14614,16 @@ var init_codex = __esm(() => {
|
|
|
15940
14614
|
return typeof raw === "string" && raw.trim().length > 0 ? raw : "You are a helpful agent working through Pairing.";
|
|
15941
14615
|
}
|
|
15942
14616
|
get threadIdPath() {
|
|
15943
|
-
return
|
|
14617
|
+
return join18(this.codexOptions.runtimeDirectory, "codex-thread-id.txt");
|
|
15944
14618
|
}
|
|
15945
14619
|
get statePath() {
|
|
15946
|
-
return
|
|
14620
|
+
return join18(this.codexOptions.runtimeDirectory, "state.json");
|
|
15947
14621
|
}
|
|
15948
14622
|
get stdoutLogPath() {
|
|
15949
|
-
return
|
|
14623
|
+
return join18(this.codexOptions.logsDirectory, "stdout.log");
|
|
15950
14624
|
}
|
|
15951
14625
|
get stderrLogPath() {
|
|
15952
|
-
return
|
|
14626
|
+
return join18(this.codexOptions.logsDirectory, "stderr.log");
|
|
15953
14627
|
}
|
|
15954
14628
|
enqueue(task) {
|
|
15955
14629
|
const next = this.serialized.then(task, task);
|
|
@@ -15978,7 +14652,7 @@ var init_codex = __esm(() => {
|
|
|
15978
14652
|
const options = this.codexOptions;
|
|
15979
14653
|
await mkdir8(options.runtimeDirectory, { recursive: true });
|
|
15980
14654
|
await mkdir8(options.logsDirectory, { recursive: true });
|
|
15981
|
-
await writeFile7(
|
|
14655
|
+
await writeFile7(join18(options.runtimeDirectory, "prompt.txt"), options.systemPrompt);
|
|
15982
14656
|
const codexExecutable = await resolveCodexExecutable2();
|
|
15983
14657
|
const child = spawn4(codexExecutable, ["app-server", ...options.launchArgs], {
|
|
15984
14658
|
cwd: options.cwd,
|
|
@@ -16695,9 +15369,9 @@ var init_codex = __esm(() => {
|
|
|
16695
15369
|
}
|
|
16696
15370
|
async request(method, params) {
|
|
16697
15371
|
const id = String(this.nextRequestId++);
|
|
16698
|
-
return new Promise((
|
|
15372
|
+
return new Promise((resolve9, reject) => {
|
|
16699
15373
|
this.pendingRequests.set(id, {
|
|
16700
|
-
resolve: (value) =>
|
|
15374
|
+
resolve: (value) => resolve9(value),
|
|
16701
15375
|
reject
|
|
16702
15376
|
});
|
|
16703
15377
|
try {
|
|
@@ -18052,8 +16726,8 @@ var init_echo = __esm(() => {
|
|
|
18052
16726
|
blockId: actionId,
|
|
18053
16727
|
approval: { version: 1, description: `Run echo tool with: ${text}`, risk: "low" }
|
|
18054
16728
|
});
|
|
18055
|
-
const decision = await new Promise((
|
|
18056
|
-
this.pendingApprovals.set(this.approvalKey(turnId, actionId), { resolve:
|
|
16729
|
+
const decision = await new Promise((resolve9) => {
|
|
16730
|
+
this.pendingApprovals.set(this.approvalKey(turnId, actionId), { resolve: resolve9 });
|
|
18057
16731
|
});
|
|
18058
16732
|
if (this.interrupted) {
|
|
18059
16733
|
this.emitTurnEnd(sessionId, turnId, "stopped");
|
|
@@ -18128,7 +16802,7 @@ var init_echo = __esm(() => {
|
|
|
18128
16802
|
delay() {
|
|
18129
16803
|
if (this.stepDelay <= 0)
|
|
18130
16804
|
return Promise.resolve();
|
|
18131
|
-
return new Promise((
|
|
16805
|
+
return new Promise((resolve9) => setTimeout(resolve9, this.stepDelay));
|
|
18132
16806
|
}
|
|
18133
16807
|
};
|
|
18134
16808
|
});
|
|
@@ -18147,8 +16821,8 @@ var init_src2 = __esm(() => {
|
|
|
18147
16821
|
|
|
18148
16822
|
// ../../apps/desktop/src/core/pairing/runtime/bridge/log.ts
|
|
18149
16823
|
import { appendFileSync, mkdirSync as mkdirSync7 } from "fs";
|
|
18150
|
-
import { join as
|
|
18151
|
-
import { homedir as
|
|
16824
|
+
import { join as join19 } from "path";
|
|
16825
|
+
import { homedir as homedir12 } from "os";
|
|
18152
16826
|
function write(level, category, message, data) {
|
|
18153
16827
|
const ts = new Date().toISOString().slice(11, 23);
|
|
18154
16828
|
const lvl = level.toUpperCase().padEnd(5);
|
|
@@ -18164,8 +16838,8 @@ function write(level, category, message, data) {
|
|
|
18164
16838
|
}
|
|
18165
16839
|
var LOG_DIR, LOG_FILE, log;
|
|
18166
16840
|
var init_log = __esm(() => {
|
|
18167
|
-
LOG_DIR =
|
|
18168
|
-
LOG_FILE =
|
|
16841
|
+
LOG_DIR = join19(homedir12(), ".scout/pairing");
|
|
16842
|
+
LOG_FILE = join19(LOG_DIR, "bridge.log");
|
|
18169
16843
|
mkdirSync7(LOG_DIR, { recursive: true });
|
|
18170
16844
|
log = {
|
|
18171
16845
|
debug: (cat, msg, data) => write("debug", cat, msg, data),
|
|
@@ -18241,11 +16915,11 @@ var init_bridge = __esm(() => {
|
|
|
18241
16915
|
});
|
|
18242
16916
|
|
|
18243
16917
|
// ../../apps/desktop/src/core/pairing/runtime/bridge/config.ts
|
|
18244
|
-
import { existsSync as
|
|
18245
|
-
import { join as
|
|
18246
|
-
import { homedir as
|
|
16918
|
+
import { existsSync as existsSync15, readFileSync as readFileSync9 } from "fs";
|
|
16919
|
+
import { join as join20 } from "path";
|
|
16920
|
+
import { homedir as homedir13 } from "os";
|
|
18247
16921
|
function loadConfigFile() {
|
|
18248
|
-
if (!
|
|
16922
|
+
if (!existsSync15(CONFIG_FILE)) {
|
|
18249
16923
|
return {};
|
|
18250
16924
|
}
|
|
18251
16925
|
try {
|
|
@@ -18306,17 +16980,17 @@ var init_config3 = __esm(() => {
|
|
|
18306
16980
|
port: 7888,
|
|
18307
16981
|
secure: true
|
|
18308
16982
|
};
|
|
18309
|
-
CONFIG_DIR =
|
|
18310
|
-
CONFIG_FILE =
|
|
16983
|
+
CONFIG_DIR = join20(homedir13(), ".scout/pairing");
|
|
16984
|
+
CONFIG_FILE = join20(CONFIG_DIR, "config.json");
|
|
18311
16985
|
});
|
|
18312
16986
|
|
|
18313
16987
|
// ../../apps/desktop/src/core/pairing/runtime/bridge/fileserver.ts
|
|
18314
16988
|
import { isAbsolute as isAbsolute2 } from "path";
|
|
18315
|
-
import { homedir as
|
|
16989
|
+
import { homedir as homedir14 } from "os";
|
|
18316
16990
|
function isAllowedPath(filePath) {
|
|
18317
16991
|
if (!isAbsolute2(filePath))
|
|
18318
16992
|
return false;
|
|
18319
|
-
const relToHome = filePath.slice(
|
|
16993
|
+
const relToHome = filePath.slice(homedir14().length + 1);
|
|
18320
16994
|
if (relToHome.startsWith(".") && !relToHome.startsWith(".claude") && !relToHome.startsWith(".scout/pairing")) {
|
|
18321
16995
|
return false;
|
|
18322
16996
|
}
|
|
@@ -18375,16 +17049,16 @@ function serveFile(url) {
|
|
|
18375
17049
|
}
|
|
18376
17050
|
var ALLOWED_ROOTS;
|
|
18377
17051
|
var init_fileserver = __esm(() => {
|
|
18378
|
-
ALLOWED_ROOTS = [
|
|
17052
|
+
ALLOWED_ROOTS = [homedir14(), "/tmp"];
|
|
18379
17053
|
});
|
|
18380
17054
|
|
|
18381
17055
|
// ../../apps/desktop/src/server/db-queries.ts
|
|
18382
17056
|
import { Database } from "bun:sqlite";
|
|
18383
|
-
import { homedir as
|
|
18384
|
-
import { join as
|
|
17057
|
+
import { homedir as homedir15 } from "os";
|
|
17058
|
+
import { join as join21 } from "path";
|
|
18385
17059
|
function resolveDbPath() {
|
|
18386
|
-
const controlHome = process.env.OPENSCOUT_CONTROL_HOME ??
|
|
18387
|
-
return
|
|
17060
|
+
const controlHome = process.env.OPENSCOUT_CONTROL_HOME ?? join21(homedir15(), ".openscout", "control-plane");
|
|
17061
|
+
return join21(controlHome, "control-plane.sqlite");
|
|
18388
17062
|
}
|
|
18389
17063
|
function db() {
|
|
18390
17064
|
if (!_db) {
|
|
@@ -18626,11 +17300,11 @@ function queryMobileAgentDetail(agentId) {
|
|
|
18626
17300
|
}
|
|
18627
17301
|
var _db = null, HOME;
|
|
18628
17302
|
var init_db_queries = __esm(() => {
|
|
18629
|
-
HOME =
|
|
17303
|
+
HOME = homedir15();
|
|
18630
17304
|
});
|
|
18631
17305
|
|
|
18632
17306
|
// ../../apps/desktop/src/core/mobile/service.ts
|
|
18633
|
-
import { basename as basename6, resolve as
|
|
17307
|
+
import { basename as basename6, resolve as resolve9 } from "path";
|
|
18634
17308
|
function normalizeTimestamp(value) {
|
|
18635
17309
|
if (!value)
|
|
18636
17310
|
return null;
|
|
@@ -19019,7 +17693,7 @@ async function createScoutSession(input, currentDirectory, deviceId) {
|
|
|
19019
17693
|
if (!rawWorkspaceId) {
|
|
19020
17694
|
throw new Error(`Invalid workspaceId.`);
|
|
19021
17695
|
}
|
|
19022
|
-
const workspaceRoot =
|
|
17696
|
+
const workspaceRoot = resolve9(rawWorkspaceId);
|
|
19023
17697
|
const projectName = basename6(workspaceRoot) || workspaceRoot;
|
|
19024
17698
|
const workspace = {
|
|
19025
17699
|
id: workspaceRoot,
|
|
@@ -19129,17 +17803,17 @@ async function deriveNewAgentName(projectName, branch, harness) {
|
|
|
19129
17803
|
}
|
|
19130
17804
|
async function createGitWorktree(projectRoot, agentName) {
|
|
19131
17805
|
const { execSync: execSync2 } = await import("child_process");
|
|
19132
|
-
const { join:
|
|
19133
|
-
const { mkdirSync: mkdirSync8, existsSync:
|
|
17806
|
+
const { join: join22 } = await import("path");
|
|
17807
|
+
const { mkdirSync: mkdirSync8, existsSync: existsSync16 } = await import("fs");
|
|
19134
17808
|
try {
|
|
19135
17809
|
execSync2("git rev-parse --git-dir", { cwd: projectRoot, stdio: "pipe" });
|
|
19136
17810
|
} catch {
|
|
19137
17811
|
return null;
|
|
19138
17812
|
}
|
|
19139
17813
|
const branchName = `scout/${agentName}`;
|
|
19140
|
-
const worktreeDir =
|
|
19141
|
-
const worktreePath =
|
|
19142
|
-
if (
|
|
17814
|
+
const worktreeDir = join22(projectRoot, ".scout-worktrees");
|
|
17815
|
+
const worktreePath = join22(worktreeDir, agentName);
|
|
17816
|
+
if (existsSync16(worktreePath)) {
|
|
19143
17817
|
return { path: worktreePath, branch: branchName };
|
|
19144
17818
|
}
|
|
19145
17819
|
mkdirSync8(worktreeDir, { recursive: true });
|
|
@@ -19184,8 +17858,8 @@ var init_service5 = __esm(async () => {
|
|
|
19184
17858
|
// ../../apps/desktop/src/core/pairing/runtime/bridge/server.ts
|
|
19185
17859
|
import { readdirSync as readdirSync2, readFileSync as readFileSync10, realpathSync, statSync as statSync3 } from "fs";
|
|
19186
17860
|
import { execSync as execSync2 } from "child_process";
|
|
19187
|
-
import { basename as basename7, isAbsolute as isAbsolute3, join as
|
|
19188
|
-
import { homedir as
|
|
17861
|
+
import { basename as basename7, isAbsolute as isAbsolute3, join as join22, relative as relative2 } from "path";
|
|
17862
|
+
import { homedir as homedir16 } from "os";
|
|
19189
17863
|
function replaySyncEvents(bridge, sessionId, lastSeq) {
|
|
19190
17864
|
return bridge.replay(sessionId, lastSeq);
|
|
19191
17865
|
}
|
|
@@ -19639,13 +18313,13 @@ function resolveMobileCurrentDirectory() {
|
|
|
19639
18313
|
}
|
|
19640
18314
|
}
|
|
19641
18315
|
function resolveWorkspaceRoot(root) {
|
|
19642
|
-
const expandedRoot = root.replace(/^~/,
|
|
18316
|
+
const expandedRoot = root.replace(/^~/, homedir16());
|
|
19643
18317
|
return realpathSync(expandedRoot);
|
|
19644
18318
|
}
|
|
19645
18319
|
function resolveWorkspacePath(root, requestedPath) {
|
|
19646
18320
|
const normalizedRoot = resolveWorkspaceRoot(root);
|
|
19647
|
-
const expandedPath = requestedPath?.replace(/^~/,
|
|
19648
|
-
const candidate = expandedPath ? isAbsolute3(expandedPath) ? expandedPath :
|
|
18321
|
+
const expandedPath = requestedPath?.replace(/^~/, homedir16());
|
|
18322
|
+
const candidate = expandedPath ? isAbsolute3(expandedPath) ? expandedPath : join22(normalizedRoot, expandedPath) : normalizedRoot;
|
|
19649
18323
|
const resolvedCandidate = realpathSync(candidate);
|
|
19650
18324
|
const rel = relative2(normalizedRoot, resolvedCandidate);
|
|
19651
18325
|
if (rel === "" || !rel.startsWith("..") && !isAbsolute3(rel)) {
|
|
@@ -19660,7 +18334,7 @@ function listDirectories(dirPath) {
|
|
|
19660
18334
|
continue;
|
|
19661
18335
|
if (name === "node_modules" || name === ".build" || name === "target")
|
|
19662
18336
|
continue;
|
|
19663
|
-
const fullPath =
|
|
18337
|
+
const fullPath = join22(dirPath, name);
|
|
19664
18338
|
try {
|
|
19665
18339
|
const stat4 = statSync3(fullPath);
|
|
19666
18340
|
if (!stat4.isDirectory())
|
|
@@ -19683,7 +18357,7 @@ function listDirectories(dirPath) {
|
|
|
19683
18357
|
return entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
19684
18358
|
}
|
|
19685
18359
|
async function discoverSessionFiles(maxAgeDays, limit) {
|
|
19686
|
-
const home =
|
|
18360
|
+
const home = homedir16();
|
|
19687
18361
|
const results = [];
|
|
19688
18362
|
const searchPaths = [
|
|
19689
18363
|
{ pattern: `${home}/.claude/projects`, agent: "claude-code" },
|
|
@@ -34591,8 +33265,8 @@ var init_zod = __esm(() => {
|
|
|
34591
33265
|
// ../../apps/desktop/src/core/pairing/runtime/bridge/router.ts
|
|
34592
33266
|
import { readFileSync as readFileSync11, readdirSync as readdirSync3, realpathSync as realpathSync2, statSync as statSync4 } from "fs";
|
|
34593
33267
|
import { execSync as execSync3 } from "child_process";
|
|
34594
|
-
import { basename as basename8, isAbsolute as isAbsolute4, join as
|
|
34595
|
-
import { homedir as
|
|
33268
|
+
import { basename as basename8, isAbsolute as isAbsolute4, join as join23, relative as relative3 } from "path";
|
|
33269
|
+
import { homedir as homedir17 } from "os";
|
|
34596
33270
|
function resolveMobileCurrentDirectory2() {
|
|
34597
33271
|
const config2 = resolveConfig();
|
|
34598
33272
|
const configuredRoot = config2.workspace?.root;
|
|
@@ -34605,13 +33279,13 @@ function resolveMobileCurrentDirectory2() {
|
|
|
34605
33279
|
}
|
|
34606
33280
|
}
|
|
34607
33281
|
function resolveWorkspaceRoot2(root) {
|
|
34608
|
-
const expandedRoot = root.replace(/^~/,
|
|
33282
|
+
const expandedRoot = root.replace(/^~/, homedir17());
|
|
34609
33283
|
return realpathSync2(expandedRoot);
|
|
34610
33284
|
}
|
|
34611
33285
|
function resolveWorkspacePath2(root, requestedPath) {
|
|
34612
33286
|
const normalizedRoot = resolveWorkspaceRoot2(root);
|
|
34613
|
-
const expandedPath = requestedPath?.replace(/^~/,
|
|
34614
|
-
const candidate = expandedPath ? isAbsolute4(expandedPath) ? expandedPath :
|
|
33287
|
+
const expandedPath = requestedPath?.replace(/^~/, homedir17());
|
|
33288
|
+
const candidate = expandedPath ? isAbsolute4(expandedPath) ? expandedPath : join23(normalizedRoot, expandedPath) : normalizedRoot;
|
|
34615
33289
|
const resolvedCandidate = realpathSync2(candidate);
|
|
34616
33290
|
const rel = relative3(normalizedRoot, resolvedCandidate);
|
|
34617
33291
|
if (rel === "" || !rel.startsWith("..") && !isAbsolute4(rel)) {
|
|
@@ -34626,7 +33300,7 @@ function listDirectories2(dirPath) {
|
|
|
34626
33300
|
continue;
|
|
34627
33301
|
if (name === "node_modules" || name === ".build" || name === "target")
|
|
34628
33302
|
continue;
|
|
34629
|
-
const fullPath =
|
|
33303
|
+
const fullPath = join23(dirPath, name);
|
|
34630
33304
|
try {
|
|
34631
33305
|
const stat4 = statSync4(fullPath);
|
|
34632
33306
|
if (!stat4.isDirectory())
|
|
@@ -34665,7 +33339,7 @@ function detectAgent2(filePath) {
|
|
|
34665
33339
|
return "unknown";
|
|
34666
33340
|
}
|
|
34667
33341
|
async function discoverSessionFiles2(maxAgeDays, limit) {
|
|
34668
|
-
const home =
|
|
33342
|
+
const home = homedir17();
|
|
34669
33343
|
const results = [];
|
|
34670
33344
|
const searchPaths = [
|
|
34671
33345
|
{ pattern: `${home}/.claude/projects`, agent: "claude-code" },
|
|
@@ -34747,23 +33421,23 @@ function bridgeEventIterable(bridge, signal) {
|
|
|
34747
33421
|
return {
|
|
34748
33422
|
[Symbol.asyncIterator]() {
|
|
34749
33423
|
const buffer = [];
|
|
34750
|
-
let
|
|
33424
|
+
let resolve10 = null;
|
|
34751
33425
|
let done = false;
|
|
34752
33426
|
const unsub = bridge.onEvent((event) => {
|
|
34753
33427
|
if (done)
|
|
34754
33428
|
return;
|
|
34755
33429
|
buffer.push(event);
|
|
34756
|
-
if (
|
|
34757
|
-
|
|
34758
|
-
|
|
33430
|
+
if (resolve10) {
|
|
33431
|
+
resolve10();
|
|
33432
|
+
resolve10 = null;
|
|
34759
33433
|
}
|
|
34760
33434
|
});
|
|
34761
33435
|
const cleanup = () => {
|
|
34762
33436
|
done = true;
|
|
34763
33437
|
unsub();
|
|
34764
|
-
if (
|
|
34765
|
-
|
|
34766
|
-
|
|
33438
|
+
if (resolve10) {
|
|
33439
|
+
resolve10();
|
|
33440
|
+
resolve10 = null;
|
|
34767
33441
|
}
|
|
34768
33442
|
};
|
|
34769
33443
|
signal?.addEventListener("abort", cleanup, { once: true });
|
|
@@ -34776,7 +33450,7 @@ function bridgeEventIterable(bridge, signal) {
|
|
|
34776
33450
|
return { done: false, value: buffer.shift() };
|
|
34777
33451
|
}
|
|
34778
33452
|
await new Promise((r) => {
|
|
34779
|
-
|
|
33453
|
+
resolve10 = r;
|
|
34780
33454
|
});
|
|
34781
33455
|
}
|
|
34782
33456
|
},
|
|
@@ -37494,15 +36168,15 @@ function resolveSelfTuple(promise2) {
|
|
|
37494
36168
|
return Unpromise.proxy(promise2).then(() => [promise2]);
|
|
37495
36169
|
}
|
|
37496
36170
|
function withResolvers() {
|
|
37497
|
-
let
|
|
36171
|
+
let resolve10;
|
|
37498
36172
|
let reject;
|
|
37499
36173
|
const promise2 = new Promise((_resolve, _reject) => {
|
|
37500
|
-
|
|
36174
|
+
resolve10 = _resolve;
|
|
37501
36175
|
reject = _reject;
|
|
37502
36176
|
});
|
|
37503
36177
|
return {
|
|
37504
36178
|
promise: promise2,
|
|
37505
|
-
resolve:
|
|
36179
|
+
resolve: resolve10,
|
|
37506
36180
|
reject
|
|
37507
36181
|
};
|
|
37508
36182
|
}
|
|
@@ -37541,8 +36215,8 @@ function timerResource(ms) {
|
|
|
37541
36215
|
return makeResource({ start() {
|
|
37542
36216
|
if (timer)
|
|
37543
36217
|
throw new Error("Timer already started");
|
|
37544
|
-
const promise2 = new Promise((
|
|
37545
|
-
timer = setTimeout(() =>
|
|
36218
|
+
const promise2 = new Promise((resolve10) => {
|
|
36219
|
+
timer = setTimeout(() => resolve10(disposablePromiseTimerResult), ms);
|
|
37546
36220
|
});
|
|
37547
36221
|
return promise2;
|
|
37548
36222
|
} }, () => {
|
|
@@ -37591,15 +36265,15 @@ function _takeWithGrace() {
|
|
|
37591
36265
|
return _takeWithGrace.apply(this, arguments);
|
|
37592
36266
|
}
|
|
37593
36267
|
function createDeferred() {
|
|
37594
|
-
let
|
|
36268
|
+
let resolve10;
|
|
37595
36269
|
let reject;
|
|
37596
36270
|
const promise2 = new Promise((res, rej) => {
|
|
37597
|
-
|
|
36271
|
+
resolve10 = res;
|
|
37598
36272
|
reject = rej;
|
|
37599
36273
|
});
|
|
37600
36274
|
return {
|
|
37601
36275
|
promise: promise2,
|
|
37602
|
-
resolve:
|
|
36276
|
+
resolve: resolve10,
|
|
37603
36277
|
reject
|
|
37604
36278
|
};
|
|
37605
36279
|
}
|
|
@@ -38575,8 +37249,8 @@ var import_objectSpread2$13, jsonContentTypeHandler, formDataContentTypeHandler,
|
|
|
38575
37249
|
status: "fulfilled",
|
|
38576
37250
|
value
|
|
38577
37251
|
};
|
|
38578
|
-
subscribers === null || subscribers === undefined || subscribers.forEach(({ resolve:
|
|
38579
|
-
|
|
37252
|
+
subscribers === null || subscribers === undefined || subscribers.forEach(({ resolve: resolve10 }) => {
|
|
37253
|
+
resolve10(value);
|
|
38580
37254
|
});
|
|
38581
37255
|
});
|
|
38582
37256
|
if ("catch" in thenReturn)
|
|
@@ -39307,14 +37981,14 @@ var init_observable = __esm(() => {
|
|
|
39307
37981
|
|
|
39308
37982
|
// ../../apps/desktop/src/core/pairing/runtime/bridge/server-trpc.ts
|
|
39309
37983
|
import { realpathSync as realpathSync3 } from "fs";
|
|
39310
|
-
import { homedir as
|
|
37984
|
+
import { homedir as homedir18 } from "os";
|
|
39311
37985
|
function resolveCurrentDirectory() {
|
|
39312
37986
|
try {
|
|
39313
37987
|
const config2 = resolveConfig();
|
|
39314
37988
|
const configuredRoot = config2.workspace?.root;
|
|
39315
37989
|
if (!configuredRoot)
|
|
39316
37990
|
return process.cwd();
|
|
39317
|
-
const expanded = configuredRoot.replace(/^~/,
|
|
37991
|
+
const expanded = configuredRoot.replace(/^~/, homedir18());
|
|
39318
37992
|
return realpathSync3(expanded);
|
|
39319
37993
|
} catch {
|
|
39320
37994
|
return process.cwd();
|
|
@@ -39432,8 +38106,8 @@ function startBridgeServerTRPC(options) {
|
|
|
39432
38106
|
}
|
|
39433
38107
|
const iterable = isObservable(result) ? observableToAsyncIterable(result, abortController.signal) : result;
|
|
39434
38108
|
const iterator = iterable[Symbol.asyncIterator]();
|
|
39435
|
-
const abortPromise = new Promise((
|
|
39436
|
-
abortController.signal.addEventListener("abort", () =>
|
|
38109
|
+
const abortPromise = new Promise((resolve10) => {
|
|
38110
|
+
abortController.signal.addEventListener("abort", () => resolve10("abort"), {
|
|
39437
38111
|
once: true
|
|
39438
38112
|
});
|
|
39439
38113
|
});
|
|
@@ -39730,7 +38404,7 @@ var init_server_trpc = __esm(async () => {
|
|
|
39730
38404
|
});
|
|
39731
38405
|
|
|
39732
38406
|
// ../../apps/desktop/src/core/pairing/runtime/runtime.ts
|
|
39733
|
-
import { homedir as
|
|
38407
|
+
import { homedir as homedir19 } from "os";
|
|
39734
38408
|
function createPairingAdapterRegistry(configAdapters) {
|
|
39735
38409
|
const adapters = {
|
|
39736
38410
|
"claude-code": createAdapter,
|
|
@@ -39807,7 +38481,7 @@ async function autoStartConfiguredSessions(bridge, sessions3) {
|
|
|
39807
38481
|
try {
|
|
39808
38482
|
const session = await bridge.createSession(entry.adapter, {
|
|
39809
38483
|
name: entry.name,
|
|
39810
|
-
cwd: entry.cwd?.replace(/^~/,
|
|
38484
|
+
cwd: entry.cwd?.replace(/^~/, homedir19()),
|
|
39811
38485
|
options: entry.options
|
|
39812
38486
|
});
|
|
39813
38487
|
console.log(`[bridge] session started: ${session.name} (${entry.adapter})`);
|
|
@@ -40078,11 +38752,11 @@ var BRIDGE_ABSENCE_GRACE_MS = 30000, ROOM_IDLE_TIMEOUT_MS = 60000;
|
|
|
40078
38752
|
|
|
40079
38753
|
// ../../apps/desktop/src/core/pairing/runtime/relay-runtime.ts
|
|
40080
38754
|
import { execSync as execSync4 } from "child_process";
|
|
40081
|
-
import { existsSync as
|
|
40082
|
-
import { homedir as
|
|
40083
|
-
import { join as
|
|
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";
|
|
40084
38758
|
function findStoredCerts() {
|
|
40085
|
-
if (!
|
|
38759
|
+
if (!existsSync16(PAIRING_DIR2)) {
|
|
40086
38760
|
return null;
|
|
40087
38761
|
}
|
|
40088
38762
|
try {
|
|
@@ -40096,8 +38770,8 @@ function findStoredCerts() {
|
|
|
40096
38770
|
return null;
|
|
40097
38771
|
}
|
|
40098
38772
|
return {
|
|
40099
|
-
cert:
|
|
40100
|
-
key:
|
|
38773
|
+
cert: join24(PAIRING_DIR2, certFile),
|
|
38774
|
+
key: join24(PAIRING_DIR2, keyFile)
|
|
40101
38775
|
};
|
|
40102
38776
|
} catch {
|
|
40103
38777
|
return null;
|
|
@@ -40118,8 +38792,8 @@ function getTailscaleHostname() {
|
|
|
40118
38792
|
}
|
|
40119
38793
|
function generateTailscaleCerts(hostname5) {
|
|
40120
38794
|
mkdirSync9(PAIRING_DIR2, { recursive: true });
|
|
40121
|
-
const certPath =
|
|
40122
|
-
const keyPath =
|
|
38795
|
+
const certPath = join24(PAIRING_DIR2, `${hostname5}.crt`);
|
|
38796
|
+
const keyPath = join24(PAIRING_DIR2, `${hostname5}.key`);
|
|
40123
38797
|
try {
|
|
40124
38798
|
pairingLog.info("relay", "generating tailscale TLS cert", { hostname: hostname5 });
|
|
40125
38799
|
execSync4(`tailscale cert --cert-file "${certPath}" --key-file "${keyPath}" "${hostname5}"`, {
|
|
@@ -40135,8 +38809,8 @@ function generateTailscaleCerts(hostname5) {
|
|
|
40135
38809
|
}
|
|
40136
38810
|
function generateSelfSignedCert(hostname5) {
|
|
40137
38811
|
mkdirSync9(PAIRING_DIR2, { recursive: true });
|
|
40138
|
-
const certPath =
|
|
40139
|
-
const keyPath =
|
|
38812
|
+
const certPath = join24(PAIRING_DIR2, `${hostname5}.crt`);
|
|
38813
|
+
const keyPath = join24(PAIRING_DIR2, `${hostname5}.key`);
|
|
40140
38814
|
try {
|
|
40141
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}"`, {
|
|
40142
38816
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -40199,7 +38873,7 @@ function startManagedRelay(port = 7889) {
|
|
|
40199
38873
|
var PAIRING_DIR2;
|
|
40200
38874
|
var init_relay_runtime = __esm(() => {
|
|
40201
38875
|
init_log2();
|
|
40202
|
-
PAIRING_DIR2 =
|
|
38876
|
+
PAIRING_DIR2 = join24(homedir20(), ".scout/pairing");
|
|
40203
38877
|
});
|
|
40204
38878
|
|
|
40205
38879
|
// ../../node_modules/.bun/uqr@0.1.3/node_modules/uqr/dist/index.mjs
|
|
@@ -41064,8 +39738,8 @@ async function runPairCommand(context, args) {
|
|
|
41064
39738
|
process.on("SIGINT", handleSignal);
|
|
41065
39739
|
process.on("SIGTERM", handleSignal);
|
|
41066
39740
|
try {
|
|
41067
|
-
await new Promise((
|
|
41068
|
-
controller.signal.addEventListener("abort", () =>
|
|
39741
|
+
await new Promise((resolve10) => {
|
|
39742
|
+
controller.signal.addEventListener("abort", () => resolve10(), { once: true });
|
|
41069
39743
|
});
|
|
41070
39744
|
} finally {
|
|
41071
39745
|
process.off("SIGINT", handleSignal);
|
|
@@ -41128,62 +39802,34 @@ var init_runtimes = __esm(() => {
|
|
|
41128
39802
|
init_service3();
|
|
41129
39803
|
});
|
|
41130
39804
|
|
|
41131
|
-
// ../../apps/desktop/src/cli/commands/send.ts
|
|
41132
|
-
var exports_send = {};
|
|
41133
|
-
__export(exports_send, {
|
|
41134
|
-
runSendCommand: () => runSendCommand
|
|
41135
|
-
});
|
|
41136
|
-
async function runSendCommand(context, args) {
|
|
41137
|
-
const options = parseSendCommandOptions(args, defaultScoutContextDirectory(context));
|
|
41138
|
-
const currentDirectory = options.currentDirectory ?? defaultScoutContextDirectory(context);
|
|
41139
|
-
const senderId = await resolveScoutSenderId(options.agentName, currentDirectory);
|
|
41140
|
-
const result = await sendScoutMessage({
|
|
41141
|
-
senderId,
|
|
41142
|
-
body: options.message,
|
|
41143
|
-
channel: options.channel,
|
|
41144
|
-
shouldSpeak: options.shouldSpeak,
|
|
41145
|
-
executionHarness: parseScoutHarness(options.harness),
|
|
41146
|
-
currentDirectory: options.currentDirectory
|
|
41147
|
-
});
|
|
41148
|
-
if (!result.usedBroker) {
|
|
41149
|
-
throw new Error("broker is not reachable");
|
|
41150
|
-
}
|
|
41151
|
-
context.output.writeValue({
|
|
41152
|
-
message: options.message,
|
|
41153
|
-
invokedTargets: result.invokedTargets,
|
|
41154
|
-
unresolvedTargets: result.unresolvedTargets
|
|
41155
|
-
}, renderScoutMessagePostResult);
|
|
41156
|
-
}
|
|
41157
|
-
var init_send = __esm(async () => {
|
|
41158
|
-
init_context();
|
|
41159
|
-
init_options();
|
|
41160
|
-
init_broker();
|
|
41161
|
-
await init_service();
|
|
41162
|
-
});
|
|
41163
|
-
|
|
41164
39805
|
// ../../apps/desktop/src/cli/commands/server.ts
|
|
41165
39806
|
var exports_server = {};
|
|
41166
39807
|
__export(exports_server, {
|
|
41167
39808
|
runServerCommand: () => runServerCommand,
|
|
41168
39809
|
resolveScoutWebServerEntry: () => resolveScoutWebServerEntry,
|
|
41169
39810
|
resolveScoutControlPlaneWebServerEntry: () => resolveScoutControlPlaneWebServerEntry,
|
|
41170
|
-
renderServerCommandHelp: () => renderServerCommandHelp
|
|
39811
|
+
renderServerCommandHelp: () => renderServerCommandHelp,
|
|
39812
|
+
normalizeServerOpenPath: () => normalizeServerOpenPath
|
|
41171
39813
|
});
|
|
41172
39814
|
import { spawn as spawn5 } from "child_process";
|
|
41173
|
-
import { existsSync as
|
|
41174
|
-
import { dirname as
|
|
41175
|
-
import { fileURLToPath as
|
|
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";
|
|
41176
39818
|
function renderServerCommandHelp() {
|
|
41177
39819
|
return [
|
|
41178
39820
|
"scout server \u2014 desktop web UI (Bun runtime)",
|
|
41179
39821
|
"",
|
|
41180
39822
|
"Usage:",
|
|
41181
39823
|
" scout server start [options]",
|
|
39824
|
+
" scout server open [options]",
|
|
41182
39825
|
" scout server control-plane start [options]",
|
|
39826
|
+
" scout server control-plane open [options]",
|
|
41183
39827
|
"",
|
|
41184
39828
|
"Subcommands:",
|
|
41185
39829
|
" start Full desktop web API + UI assets (default stack).",
|
|
39830
|
+
" open Open the full web UI and start it on demand if needed.",
|
|
41186
39831
|
" control-plane start Pairing + relay/shell activity only (`@openscout/web` surface).",
|
|
39832
|
+
" control-plane open Open the control-plane UI and start it on demand if needed.",
|
|
41187
39833
|
"",
|
|
41188
39834
|
"Options:",
|
|
41189
39835
|
" --port <n> Listen port (default 3200; env SCOUT_WEB_PORT)",
|
|
@@ -41191,6 +39837,7 @@ function renderServerCommandHelp() {
|
|
|
41191
39837
|
" --static-root DIR Static client root (env SCOUT_STATIC_ROOT)",
|
|
41192
39838
|
" --vite-url URL Dev proxy target for non-API routes (env SCOUT_VITE_URL)",
|
|
41193
39839
|
" --cwd DIR Workspace / setup root (env OPENSCOUT_SETUP_CWD)",
|
|
39840
|
+
" --path PATH Browser path for `open` (default /)",
|
|
41194
39841
|
"",
|
|
41195
39842
|
"Requires `bun` on PATH.",
|
|
41196
39843
|
"Published installs include dist/client for the full web UI and dist/control-plane-client",
|
|
@@ -41200,31 +39847,32 @@ function renderServerCommandHelp() {
|
|
|
41200
39847
|
`);
|
|
41201
39848
|
}
|
|
41202
39849
|
function resolveScoutWebServerEntry() {
|
|
41203
|
-
const mainDir =
|
|
41204
|
-
const bundled =
|
|
41205
|
-
if (
|
|
39850
|
+
const mainDir = dirname11(fileURLToPath8(import.meta.url));
|
|
39851
|
+
const bundled = join25(mainDir, "scout-web-server.mjs");
|
|
39852
|
+
if (existsSync17(bundled)) {
|
|
41206
39853
|
return bundled;
|
|
41207
39854
|
}
|
|
41208
|
-
const source =
|
|
41209
|
-
if (
|
|
39855
|
+
const source = fileURLToPath8(new URL("../../server/index.ts", import.meta.url));
|
|
39856
|
+
if (existsSync17(source)) {
|
|
41210
39857
|
return source;
|
|
41211
39858
|
}
|
|
41212
39859
|
throw new ScoutCliError("Could not find Scout web server entry. Rebuild @openscout/scout or run from the OpenScout repository.");
|
|
41213
39860
|
}
|
|
41214
39861
|
function resolveScoutControlPlaneWebServerEntry() {
|
|
41215
|
-
const mainDir =
|
|
41216
|
-
const bundled =
|
|
41217
|
-
if (
|
|
39862
|
+
const mainDir = dirname11(fileURLToPath8(import.meta.url));
|
|
39863
|
+
const bundled = join25(mainDir, "scout-control-plane-web.mjs");
|
|
39864
|
+
if (existsSync17(bundled)) {
|
|
41218
39865
|
return bundled;
|
|
41219
39866
|
}
|
|
41220
|
-
const source =
|
|
41221
|
-
if (
|
|
39867
|
+
const source = fileURLToPath8(new URL("../../server/control-plane-index.ts", import.meta.url));
|
|
39868
|
+
if (existsSync17(source)) {
|
|
41222
39869
|
return source;
|
|
41223
39870
|
}
|
|
41224
39871
|
throw new ScoutCliError("Could not find Scout control-plane web server entry. Rebuild @openscout/scout or run from the OpenScout repository.");
|
|
41225
39872
|
}
|
|
41226
|
-
function
|
|
39873
|
+
function parseServerFlags(args) {
|
|
41227
39874
|
const env = {};
|
|
39875
|
+
let openPath = "/";
|
|
41228
39876
|
for (let i = 0;i < args.length; i++) {
|
|
41229
39877
|
const a = args[i];
|
|
41230
39878
|
if (a === "--port") {
|
|
@@ -41259,39 +39907,44 @@ function parseServerStartFlags(args) {
|
|
|
41259
39907
|
env.OPENSCOUT_SETUP_CWD = v;
|
|
41260
39908
|
continue;
|
|
41261
39909
|
}
|
|
39910
|
+
if (a === "--path") {
|
|
39911
|
+
const v = args[++i];
|
|
39912
|
+
if (!v)
|
|
39913
|
+
throw new ScoutCliError("--path requires a value");
|
|
39914
|
+
openPath = v;
|
|
39915
|
+
continue;
|
|
39916
|
+
}
|
|
39917
|
+
if (a.startsWith("--port=")) {
|
|
39918
|
+
env.SCOUT_WEB_PORT = a.slice("--port=".length);
|
|
39919
|
+
continue;
|
|
39920
|
+
}
|
|
39921
|
+
if (a.startsWith("--static-root=")) {
|
|
39922
|
+
env.SCOUT_STATIC_ROOT = a.slice("--static-root=".length);
|
|
39923
|
+
continue;
|
|
39924
|
+
}
|
|
39925
|
+
if (a.startsWith("--vite-url=")) {
|
|
39926
|
+
env.SCOUT_VITE_URL = a.slice("--vite-url=".length);
|
|
39927
|
+
continue;
|
|
39928
|
+
}
|
|
39929
|
+
if (a.startsWith("--cwd=")) {
|
|
39930
|
+
env.OPENSCOUT_SETUP_CWD = a.slice("--cwd=".length);
|
|
39931
|
+
continue;
|
|
39932
|
+
}
|
|
39933
|
+
if (a.startsWith("--path=")) {
|
|
39934
|
+
openPath = a.slice("--path=".length);
|
|
39935
|
+
continue;
|
|
39936
|
+
}
|
|
41262
39937
|
throw new ScoutCliError(`unknown option: ${a}`);
|
|
41263
39938
|
}
|
|
41264
|
-
return { env };
|
|
39939
|
+
return { env, openPath };
|
|
41265
39940
|
}
|
|
41266
39941
|
function resolveBundledStaticClientRoot(entry, mode) {
|
|
41267
|
-
const entryDir =
|
|
41268
|
-
const clientDirectory = mode === "control-plane" ?
|
|
41269
|
-
const indexPath =
|
|
41270
|
-
return
|
|
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;
|
|
41271
39946
|
}
|
|
41272
|
-
|
|
41273
|
-
if (args.length === 0 || args[0] === "help" || args[0] === "--help" || args[0] === "-h") {
|
|
41274
|
-
context.output.writeText(renderServerCommandHelp());
|
|
41275
|
-
return;
|
|
41276
|
-
}
|
|
41277
|
-
let flagArgs;
|
|
41278
|
-
let entry;
|
|
41279
|
-
let mode;
|
|
41280
|
-
if (args[0] === "start") {
|
|
41281
|
-
flagArgs = args.slice(1);
|
|
41282
|
-
entry = resolveScoutWebServerEntry();
|
|
41283
|
-
mode = "full";
|
|
41284
|
-
} else if (args[0] === "control-plane") {
|
|
41285
|
-
if (args[1] !== "start") {
|
|
41286
|
-
throw new ScoutCliError("expected: scout server control-plane start");
|
|
41287
|
-
}
|
|
41288
|
-
flagArgs = args.slice(2);
|
|
41289
|
-
entry = resolveScoutControlPlaneWebServerEntry();
|
|
41290
|
-
mode = "control-plane";
|
|
41291
|
-
} else {
|
|
41292
|
-
throw new ScoutCliError(`unknown subcommand: ${args[0]} (try: scout server start)`);
|
|
41293
|
-
}
|
|
41294
|
-
const { env: flagEnv } = parseServerStartFlags(flagArgs);
|
|
39947
|
+
function buildMergedServerEnv(entry, mode, flagEnv) {
|
|
41295
39948
|
const bundledStaticClientRoot = resolveBundledStaticClientRoot(entry, mode);
|
|
41296
39949
|
const autoEnv = {};
|
|
41297
39950
|
if (bundledStaticClientRoot) {
|
|
@@ -41301,9 +39954,254 @@ async function runServerCommand(context, args) {
|
|
|
41301
39954
|
autoEnv.SCOUT_STATIC_ROOT = bundledStaticClientRoot;
|
|
41302
39955
|
}
|
|
41303
39956
|
}
|
|
41304
|
-
|
|
39957
|
+
return { ...process.env, ...autoEnv, ...flagEnv };
|
|
39958
|
+
}
|
|
39959
|
+
function parseServerSelection(args) {
|
|
39960
|
+
if (args[0] === "start") {
|
|
39961
|
+
return {
|
|
39962
|
+
action: "start",
|
|
39963
|
+
flagArgs: args.slice(1),
|
|
39964
|
+
entry: resolveScoutWebServerEntry(),
|
|
39965
|
+
mode: "full"
|
|
39966
|
+
};
|
|
39967
|
+
}
|
|
39968
|
+
if (args[0] === "open") {
|
|
39969
|
+
return {
|
|
39970
|
+
action: "open",
|
|
39971
|
+
flagArgs: args.slice(1),
|
|
39972
|
+
entry: resolveScoutWebServerEntry(),
|
|
39973
|
+
mode: "full"
|
|
39974
|
+
};
|
|
39975
|
+
}
|
|
39976
|
+
if (args[0] === "control-plane") {
|
|
39977
|
+
if (args[1] !== "start" && args[1] !== "open") {
|
|
39978
|
+
throw new ScoutCliError("expected: scout server control-plane <start|open>");
|
|
39979
|
+
}
|
|
39980
|
+
return {
|
|
39981
|
+
action: args[1],
|
|
39982
|
+
flagArgs: args.slice(2),
|
|
39983
|
+
entry: resolveScoutControlPlaneWebServerEntry(),
|
|
39984
|
+
mode: "control-plane"
|
|
39985
|
+
};
|
|
39986
|
+
}
|
|
39987
|
+
throw new ScoutCliError(`unknown subcommand: ${args[0]} (try: scout server open)`);
|
|
39988
|
+
}
|
|
39989
|
+
function normalizeServerOpenPath(value) {
|
|
39990
|
+
const trimmed = value.trim();
|
|
39991
|
+
if (!trimmed) {
|
|
39992
|
+
return "/";
|
|
39993
|
+
}
|
|
39994
|
+
if (trimmed.startsWith("http://") || trimmed.startsWith("https://")) {
|
|
39995
|
+
throw new ScoutCliError("--path must be a local path, not an absolute URL");
|
|
39996
|
+
}
|
|
39997
|
+
if (trimmed.startsWith("/")) {
|
|
39998
|
+
return trimmed;
|
|
39999
|
+
}
|
|
40000
|
+
return `/${trimmed}`;
|
|
40001
|
+
}
|
|
40002
|
+
function resolveServerPort(env) {
|
|
40003
|
+
const raw2 = env.SCOUT_WEB_PORT?.trim() || "3200";
|
|
40004
|
+
const port = Number.parseInt(raw2, 10);
|
|
40005
|
+
if (!Number.isFinite(port) || port <= 0) {
|
|
40006
|
+
throw new ScoutCliError(`invalid port: ${raw2}`);
|
|
40007
|
+
}
|
|
40008
|
+
return port;
|
|
40009
|
+
}
|
|
40010
|
+
function resolveExpectedCurrentDirectory(env) {
|
|
40011
|
+
return resolve10(env.OPENSCOUT_SETUP_CWD?.trim() || process.cwd());
|
|
40012
|
+
}
|
|
40013
|
+
function renderModeLabel(mode) {
|
|
40014
|
+
return mode === "control-plane" ? "Scout control plane" : "Scout";
|
|
40015
|
+
}
|
|
40016
|
+
function renderSurfaceLabel(surface) {
|
|
40017
|
+
switch (surface) {
|
|
40018
|
+
case "control-plane":
|
|
40019
|
+
return "control-plane";
|
|
40020
|
+
case "openscout-web":
|
|
40021
|
+
return "@openscout/web";
|
|
40022
|
+
case "full":
|
|
40023
|
+
default:
|
|
40024
|
+
return "full";
|
|
40025
|
+
}
|
|
40026
|
+
}
|
|
40027
|
+
function renderServerOpenResult(result) {
|
|
40028
|
+
const prefix = result.mode === "control-plane" ? "Opened Scout control plane" : "Opened Scout";
|
|
40029
|
+
return `${prefix} at ${result.url}${result.reusedExistingServer ? "" : " (started server)"}`;
|
|
40030
|
+
}
|
|
40031
|
+
function healthUrlForPort(port) {
|
|
40032
|
+
return new URL(`/api/health`, `http://127.0.0.1:${port}`);
|
|
40033
|
+
}
|
|
40034
|
+
async function probeScoutServer(port) {
|
|
40035
|
+
const controller = new AbortController;
|
|
40036
|
+
const timeout = setTimeout(() => controller.abort(), SERVER_HEALTH_TIMEOUT_MS);
|
|
40037
|
+
try {
|
|
40038
|
+
const response = await fetch(healthUrlForPort(port), {
|
|
40039
|
+
headers: { accept: "application/json" },
|
|
40040
|
+
signal: controller.signal
|
|
40041
|
+
});
|
|
40042
|
+
if (!response.ok) {
|
|
40043
|
+
return {
|
|
40044
|
+
status: "non-scout",
|
|
40045
|
+
statusCode: response.status
|
|
40046
|
+
};
|
|
40047
|
+
}
|
|
40048
|
+
let body;
|
|
40049
|
+
try {
|
|
40050
|
+
body = await response.json();
|
|
40051
|
+
} catch {
|
|
40052
|
+
return {
|
|
40053
|
+
status: "non-scout",
|
|
40054
|
+
statusCode: response.status
|
|
40055
|
+
};
|
|
40056
|
+
}
|
|
40057
|
+
if (body.ok === true && (body.surface === "full" || body.surface === "control-plane" || body.surface === "openscout-web") && typeof body.currentDirectory === "string") {
|
|
40058
|
+
return {
|
|
40059
|
+
status: "healthy",
|
|
40060
|
+
health: {
|
|
40061
|
+
ok: true,
|
|
40062
|
+
surface: body.surface,
|
|
40063
|
+
currentDirectory: body.currentDirectory
|
|
40064
|
+
}
|
|
40065
|
+
};
|
|
40066
|
+
}
|
|
40067
|
+
return {
|
|
40068
|
+
status: "non-scout",
|
|
40069
|
+
statusCode: response.status
|
|
40070
|
+
};
|
|
40071
|
+
} catch {
|
|
40072
|
+
return { status: "unreachable" };
|
|
40073
|
+
} finally {
|
|
40074
|
+
clearTimeout(timeout);
|
|
40075
|
+
}
|
|
40076
|
+
}
|
|
40077
|
+
async function openBrowser(url2) {
|
|
40078
|
+
await new Promise((resolvePromise, rejectPromise) => {
|
|
40079
|
+
let command;
|
|
40080
|
+
let args;
|
|
40081
|
+
if (process.platform === "darwin") {
|
|
40082
|
+
command = "open";
|
|
40083
|
+
args = [url2];
|
|
40084
|
+
} else if (process.platform === "win32") {
|
|
40085
|
+
command = "cmd";
|
|
40086
|
+
args = ["/c", "start", "", url2];
|
|
40087
|
+
} else {
|
|
40088
|
+
command = "xdg-open";
|
|
40089
|
+
args = [url2];
|
|
40090
|
+
}
|
|
40091
|
+
const child = spawn5(command, args, {
|
|
40092
|
+
detached: true,
|
|
40093
|
+
stdio: "ignore",
|
|
40094
|
+
windowsHide: true
|
|
40095
|
+
});
|
|
40096
|
+
child.once("error", (error48) => {
|
|
40097
|
+
if (error48.code === "ENOENT") {
|
|
40098
|
+
rejectPromise(new ScoutCliError(`could not open a browser automatically; ${command} is not available`));
|
|
40099
|
+
return;
|
|
40100
|
+
}
|
|
40101
|
+
rejectPromise(error48);
|
|
40102
|
+
});
|
|
40103
|
+
child.once("spawn", () => {
|
|
40104
|
+
child.unref();
|
|
40105
|
+
resolvePromise();
|
|
40106
|
+
});
|
|
40107
|
+
});
|
|
40108
|
+
}
|
|
40109
|
+
async function spawnDetachedServer(entry, env) {
|
|
41305
40110
|
await new Promise((resolvePromise, rejectPromise) => {
|
|
41306
40111
|
const child = spawn5("bun", ["run", entry], {
|
|
40112
|
+
detached: true,
|
|
40113
|
+
stdio: "ignore",
|
|
40114
|
+
env,
|
|
40115
|
+
windowsHide: true
|
|
40116
|
+
});
|
|
40117
|
+
child.once("error", (error48) => {
|
|
40118
|
+
if (error48.code === "ENOENT") {
|
|
40119
|
+
rejectPromise(new ScoutCliError("`bun` was not found on PATH. Install Bun (https://bun.sh) to run scout server."));
|
|
40120
|
+
return;
|
|
40121
|
+
}
|
|
40122
|
+
rejectPromise(error48);
|
|
40123
|
+
});
|
|
40124
|
+
child.once("spawn", () => {
|
|
40125
|
+
child.unref();
|
|
40126
|
+
resolvePromise();
|
|
40127
|
+
});
|
|
40128
|
+
});
|
|
40129
|
+
}
|
|
40130
|
+
async function waitForScoutServer(port, mode, expectedCurrentDirectory) {
|
|
40131
|
+
const deadline = Date.now() + SERVER_OPEN_TIMEOUT_MS;
|
|
40132
|
+
while (Date.now() < deadline) {
|
|
40133
|
+
const probe = await probeScoutServer(port);
|
|
40134
|
+
if (probe.status === "healthy") {
|
|
40135
|
+
const actualCurrentDirectory = resolve10(probe.health.currentDirectory);
|
|
40136
|
+
if (probe.health.surface !== mode) {
|
|
40137
|
+
throw new ScoutCliError(`port ${port} is serving Scout ${renderSurfaceLabel(probe.health.surface)}, not ${renderModeLabel(mode)}.`);
|
|
40138
|
+
}
|
|
40139
|
+
if (actualCurrentDirectory !== expectedCurrentDirectory) {
|
|
40140
|
+
throw new ScoutCliError(`port ${port} is already serving Scout for ${actualCurrentDirectory}, not ${expectedCurrentDirectory}.`);
|
|
40141
|
+
}
|
|
40142
|
+
return;
|
|
40143
|
+
}
|
|
40144
|
+
if (probe.status === "non-scout") {
|
|
40145
|
+
throw new ScoutCliError(`port ${port} is already serving another HTTP app or an older Scout server; choose a different --port.`);
|
|
40146
|
+
}
|
|
40147
|
+
await new Promise((resolvePromise) => setTimeout(resolvePromise, 250));
|
|
40148
|
+
}
|
|
40149
|
+
throw new ScoutCliError(`timed out waiting for ${renderModeLabel(mode)} on port ${port}`);
|
|
40150
|
+
}
|
|
40151
|
+
async function openScoutServer(options) {
|
|
40152
|
+
const port = resolveServerPort(options.env);
|
|
40153
|
+
const expectedCurrentDirectory = resolveExpectedCurrentDirectory(options.env);
|
|
40154
|
+
const browserUrl = new URL(normalizeServerOpenPath(options.openPath), `http://127.0.0.1:${port}`).toString();
|
|
40155
|
+
const probe = await probeScoutServer(port);
|
|
40156
|
+
if (probe.status === "healthy") {
|
|
40157
|
+
const actualCurrentDirectory = resolve10(probe.health.currentDirectory);
|
|
40158
|
+
if (probe.health.surface !== options.mode) {
|
|
40159
|
+
throw new ScoutCliError(`port ${port} is already serving Scout ${renderSurfaceLabel(probe.health.surface)}, not ${renderModeLabel(options.mode)}.`);
|
|
40160
|
+
}
|
|
40161
|
+
if (actualCurrentDirectory !== expectedCurrentDirectory) {
|
|
40162
|
+
throw new ScoutCliError(`port ${port} is already serving Scout for ${actualCurrentDirectory}, not ${expectedCurrentDirectory}.`);
|
|
40163
|
+
}
|
|
40164
|
+
await openBrowser(browserUrl);
|
|
40165
|
+
return {
|
|
40166
|
+
url: browserUrl,
|
|
40167
|
+
port,
|
|
40168
|
+
mode: options.mode,
|
|
40169
|
+
reusedExistingServer: true
|
|
40170
|
+
};
|
|
40171
|
+
}
|
|
40172
|
+
if (probe.status === "non-scout") {
|
|
40173
|
+
throw new ScoutCliError(`port ${port} is already serving another HTTP app or an older Scout server; choose a different --port.`);
|
|
40174
|
+
}
|
|
40175
|
+
await spawnDetachedServer(options.entry, options.env);
|
|
40176
|
+
await waitForScoutServer(port, options.mode, expectedCurrentDirectory);
|
|
40177
|
+
await openBrowser(browserUrl);
|
|
40178
|
+
return {
|
|
40179
|
+
url: browserUrl,
|
|
40180
|
+
port,
|
|
40181
|
+
mode: options.mode,
|
|
40182
|
+
reusedExistingServer: false
|
|
40183
|
+
};
|
|
40184
|
+
}
|
|
40185
|
+
async function runServerCommand(context, args) {
|
|
40186
|
+
if (args.length === 0 || args[0] === "help" || args[0] === "--help" || args[0] === "-h") {
|
|
40187
|
+
context.output.writeText(renderServerCommandHelp());
|
|
40188
|
+
return;
|
|
40189
|
+
}
|
|
40190
|
+
const selection = parseServerSelection(args);
|
|
40191
|
+
const { env: flagEnv, openPath } = parseServerFlags(selection.flagArgs);
|
|
40192
|
+
const mergedEnv = buildMergedServerEnv(selection.entry, selection.mode, flagEnv);
|
|
40193
|
+
if (selection.action === "open") {
|
|
40194
|
+
const result = await openScoutServer({
|
|
40195
|
+
entry: selection.entry,
|
|
40196
|
+
mode: selection.mode,
|
|
40197
|
+
env: mergedEnv,
|
|
40198
|
+
openPath
|
|
40199
|
+
});
|
|
40200
|
+
context.output.writeValue(result, renderServerOpenResult);
|
|
40201
|
+
return;
|
|
40202
|
+
}
|
|
40203
|
+
await new Promise((resolvePromise, rejectPromise) => {
|
|
40204
|
+
const child = spawn5("bun", ["run", selection.entry], {
|
|
41307
40205
|
stdio: "inherit",
|
|
41308
40206
|
env: mergedEnv
|
|
41309
40207
|
});
|
|
@@ -41331,13 +40229,14 @@ async function runServerCommand(context, args) {
|
|
|
41331
40229
|
});
|
|
41332
40230
|
});
|
|
41333
40231
|
}
|
|
40232
|
+
var SERVER_OPEN_TIMEOUT_MS = 15000, SERVER_HEALTH_TIMEOUT_MS = 1500;
|
|
41334
40233
|
var init_server2 = __esm(() => {
|
|
41335
40234
|
init_errors();
|
|
41336
40235
|
});
|
|
41337
40236
|
|
|
41338
40237
|
// ../../apps/desktop/src/cli/commands/setup.ts
|
|
41339
|
-
var
|
|
41340
|
-
__export(
|
|
40238
|
+
var exports_setup = {};
|
|
40239
|
+
__export(exports_setup, {
|
|
41341
40240
|
runSetupCommand: () => runSetupCommand
|
|
41342
40241
|
});
|
|
41343
40242
|
async function runSetupCommand(context, args) {
|
|
@@ -41359,7 +40258,7 @@ __export(exports_speak, {
|
|
|
41359
40258
|
async function runSpeakCommand(context, args) {
|
|
41360
40259
|
const options = parseSendCommandOptions(args, defaultScoutContextDirectory(context));
|
|
41361
40260
|
const currentDirectory = options.currentDirectory ?? defaultScoutContextDirectory(context);
|
|
41362
|
-
const senderId = await resolveScoutSenderId(options.agentName, currentDirectory);
|
|
40261
|
+
const senderId = await resolveScoutSenderId(options.agentName, currentDirectory, context.env);
|
|
41363
40262
|
const config3 = await loadScoutRelayConfig();
|
|
41364
40263
|
const voice = getScoutVoiceForChannel(config3, "voice");
|
|
41365
40264
|
await acquireScoutOnAir(senderId);
|
|
@@ -41382,6 +40281,9 @@ async function runSpeakCommand(context, args) {
|
|
|
41382
40281
|
if (!result.usedBroker) {
|
|
41383
40282
|
throw new Error("broker is not reachable");
|
|
41384
40283
|
}
|
|
40284
|
+
if (result.unresolvedTargets.length > 0) {
|
|
40285
|
+
throw new Error(formatScoutSendRoutingError(result.unresolvedTargets));
|
|
40286
|
+
}
|
|
41385
40287
|
context.output.writeValue({
|
|
41386
40288
|
message: options.message,
|
|
41387
40289
|
invokedTargets: result.invokedTargets,
|
|
@@ -41392,7 +40294,10 @@ var init_speak = __esm(async () => {
|
|
|
41392
40294
|
init_context();
|
|
41393
40295
|
init_options();
|
|
41394
40296
|
init_broker();
|
|
41395
|
-
await
|
|
40297
|
+
await __promiseAll([
|
|
40298
|
+
init_service(),
|
|
40299
|
+
init_send()
|
|
40300
|
+
]);
|
|
41396
40301
|
});
|
|
41397
40302
|
|
|
41398
40303
|
// ../../node_modules/.bun/@opentui+core@0.1.96+a7e4efcb39f2fc50/node_modules/@opentui/core/assets/javascript/highlights.scm
|
|
@@ -41444,11 +40349,11 @@ import { EventEmitter } from "events";
|
|
|
41444
40349
|
import { Buffer as Buffer2 } from "buffer";
|
|
41445
40350
|
import { Buffer as Buffer3 } from "buffer";
|
|
41446
40351
|
import { EventEmitter as EventEmitter2 } from "events";
|
|
41447
|
-
import { resolve as
|
|
41448
|
-
import { fileURLToPath as
|
|
40352
|
+
import { resolve as resolve11, dirname as dirname12 } from "path";
|
|
40353
|
+
import { fileURLToPath as fileURLToPath9 } from "url";
|
|
41449
40354
|
import { resolve as resolve22, isAbsolute as isAbsolute5, parse as parse6 } from "path";
|
|
41450
|
-
import { existsSync as
|
|
41451
|
-
import { basename as basename9, join as
|
|
40355
|
+
import { existsSync as existsSync18 } from "fs";
|
|
40356
|
+
import { basename as basename9, join as join26 } from "path";
|
|
41452
40357
|
import os from "os";
|
|
41453
40358
|
import path2 from "path";
|
|
41454
40359
|
import { EventEmitter as EventEmitter3 } from "events";
|
|
@@ -44580,13 +43485,13 @@ class DebounceController {
|
|
|
44580
43485
|
}
|
|
44581
43486
|
debounce(id, ms, fn) {
|
|
44582
43487
|
const scopeMap = TIMERS_MAP.get(this.scopeId);
|
|
44583
|
-
return new Promise((
|
|
43488
|
+
return new Promise((resolve13, reject) => {
|
|
44584
43489
|
if (scopeMap.has(id)) {
|
|
44585
43490
|
clearTimeout(scopeMap.get(id));
|
|
44586
43491
|
}
|
|
44587
43492
|
const timerId = setTimeout(() => {
|
|
44588
43493
|
try {
|
|
44589
|
-
|
|
43494
|
+
resolve13(fn());
|
|
44590
43495
|
} catch (error48) {
|
|
44591
43496
|
reject(error48);
|
|
44592
43497
|
}
|
|
@@ -44676,25 +43581,25 @@ function getParsers() {
|
|
|
44676
43581
|
filetype: "javascript",
|
|
44677
43582
|
aliases: ["javascriptreact"],
|
|
44678
43583
|
queries: {
|
|
44679
|
-
highlights: [
|
|
43584
|
+
highlights: [resolve11(dirname12(fileURLToPath9(import.meta.url)), highlights_default)]
|
|
44680
43585
|
},
|
|
44681
|
-
wasm:
|
|
43586
|
+
wasm: resolve11(dirname12(fileURLToPath9(import.meta.url)), tree_sitter_javascript_default)
|
|
44682
43587
|
},
|
|
44683
43588
|
{
|
|
44684
43589
|
filetype: "typescript",
|
|
44685
43590
|
aliases: ["typescriptreact"],
|
|
44686
43591
|
queries: {
|
|
44687
|
-
highlights: [
|
|
43592
|
+
highlights: [resolve11(dirname12(fileURLToPath9(import.meta.url)), highlights_default2)]
|
|
44688
43593
|
},
|
|
44689
|
-
wasm:
|
|
43594
|
+
wasm: resolve11(dirname12(fileURLToPath9(import.meta.url)), tree_sitter_typescript_default)
|
|
44690
43595
|
},
|
|
44691
43596
|
{
|
|
44692
43597
|
filetype: "markdown",
|
|
44693
43598
|
queries: {
|
|
44694
|
-
highlights: [
|
|
44695
|
-
injections: [
|
|
43599
|
+
highlights: [resolve11(dirname12(fileURLToPath9(import.meta.url)), highlights_default3)],
|
|
43600
|
+
injections: [resolve11(dirname12(fileURLToPath9(import.meta.url)), injections_default)]
|
|
44696
43601
|
},
|
|
44697
|
-
wasm:
|
|
43602
|
+
wasm: resolve11(dirname12(fileURLToPath9(import.meta.url)), tree_sitter_markdown_default),
|
|
44698
43603
|
injectionMapping: {
|
|
44699
43604
|
nodeTypes: {
|
|
44700
43605
|
inline: "markdown_inline",
|
|
@@ -44717,16 +43622,16 @@ function getParsers() {
|
|
|
44717
43622
|
{
|
|
44718
43623
|
filetype: "markdown_inline",
|
|
44719
43624
|
queries: {
|
|
44720
|
-
highlights: [
|
|
43625
|
+
highlights: [resolve11(dirname12(fileURLToPath9(import.meta.url)), highlights_default4)]
|
|
44721
43626
|
},
|
|
44722
|
-
wasm:
|
|
43627
|
+
wasm: resolve11(dirname12(fileURLToPath9(import.meta.url)), tree_sitter_markdown_inline_default)
|
|
44723
43628
|
},
|
|
44724
43629
|
{
|
|
44725
43630
|
filetype: "zig",
|
|
44726
43631
|
queries: {
|
|
44727
|
-
highlights: [
|
|
43632
|
+
highlights: [resolve11(dirname12(fileURLToPath9(import.meta.url)), highlights_default5)]
|
|
44728
43633
|
},
|
|
44729
|
-
wasm:
|
|
43634
|
+
wasm: resolve11(dirname12(fileURLToPath9(import.meta.url)), tree_sitter_zig_default)
|
|
44730
43635
|
}
|
|
44731
43636
|
];
|
|
44732
43637
|
}
|
|
@@ -44739,7 +43644,7 @@ function getBunfsRootPath() {
|
|
|
44739
43644
|
return process.platform === "win32" ? "B:\\~BUN\\root" : "/$bunfs/root";
|
|
44740
43645
|
}
|
|
44741
43646
|
function normalizeBunfsPath(fileName) {
|
|
44742
|
-
return
|
|
43647
|
+
return join26(getBunfsRootPath(), basename9(fileName));
|
|
44743
43648
|
}
|
|
44744
43649
|
function addDefaultParsers(parsers) {
|
|
44745
43650
|
for (const parser of parsers) {
|
|
@@ -55661,7 +54566,7 @@ var init_index_vy1rm1x3 = __esm(async () => {
|
|
|
55661
54566
|
worker_path = this.options.workerPath;
|
|
55662
54567
|
} else {
|
|
55663
54568
|
worker_path = new URL("./parser.worker.js", import.meta.url).href;
|
|
55664
|
-
if (!
|
|
54569
|
+
if (!existsSync18(resolve22(import.meta.dirname, "parser.worker.js"))) {
|
|
55665
54570
|
worker_path = new URL("./parser.worker.ts", import.meta.url).href;
|
|
55666
54571
|
}
|
|
55667
54572
|
}
|
|
@@ -73962,14 +72867,14 @@ See https://react.dev/link/invalid-hook-call for tips about how to debug and fix
|
|
|
73962
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. ");
|
|
73963
72868
|
actScopeDepth = prevActScopeDepth;
|
|
73964
72869
|
}
|
|
73965
|
-
function recursivelyFlushAsyncActWork(returnValue,
|
|
72870
|
+
function recursivelyFlushAsyncActWork(returnValue, resolve13, reject) {
|
|
73966
72871
|
var queue = ReactSharedInternals.actQueue;
|
|
73967
72872
|
if (queue !== null)
|
|
73968
72873
|
if (queue.length !== 0)
|
|
73969
72874
|
try {
|
|
73970
72875
|
flushActQueue(queue);
|
|
73971
72876
|
enqueueTask(function() {
|
|
73972
|
-
return recursivelyFlushAsyncActWork(returnValue,
|
|
72877
|
+
return recursivelyFlushAsyncActWork(returnValue, resolve13, reject);
|
|
73973
72878
|
});
|
|
73974
72879
|
return;
|
|
73975
72880
|
} catch (error48) {
|
|
@@ -73977,7 +72882,7 @@ See https://react.dev/link/invalid-hook-call for tips about how to debug and fix
|
|
|
73977
72882
|
}
|
|
73978
72883
|
else
|
|
73979
72884
|
ReactSharedInternals.actQueue = null;
|
|
73980
|
-
0 < ReactSharedInternals.thrownErrors.length ? (queue = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, reject(queue)) :
|
|
72885
|
+
0 < ReactSharedInternals.thrownErrors.length ? (queue = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, reject(queue)) : resolve13(returnValue);
|
|
73981
72886
|
}
|
|
73982
72887
|
function flushActQueue(queue) {
|
|
73983
72888
|
if (!isFlushing) {
|
|
@@ -74153,14 +73058,14 @@ See https://react.dev/link/invalid-hook-call for tips about how to debug and fix
|
|
|
74153
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 () => ...);"));
|
|
74154
73059
|
});
|
|
74155
73060
|
return {
|
|
74156
|
-
then: function(
|
|
73061
|
+
then: function(resolve13, reject) {
|
|
74157
73062
|
didAwaitActCall = true;
|
|
74158
73063
|
thenable.then(function(returnValue) {
|
|
74159
73064
|
popActScope(prevActQueue, prevActScopeDepth);
|
|
74160
73065
|
if (prevActScopeDepth === 0) {
|
|
74161
73066
|
try {
|
|
74162
73067
|
flushActQueue(queue), enqueueTask(function() {
|
|
74163
|
-
return recursivelyFlushAsyncActWork(returnValue,
|
|
73068
|
+
return recursivelyFlushAsyncActWork(returnValue, resolve13, reject);
|
|
74164
73069
|
});
|
|
74165
73070
|
} catch (error$0) {
|
|
74166
73071
|
ReactSharedInternals.thrownErrors.push(error$0);
|
|
@@ -74171,7 +73076,7 @@ See https://react.dev/link/invalid-hook-call for tips about how to debug and fix
|
|
|
74171
73076
|
reject(_thrownError);
|
|
74172
73077
|
}
|
|
74173
73078
|
} else
|
|
74174
|
-
|
|
73079
|
+
resolve13(returnValue);
|
|
74175
73080
|
}, function(error48) {
|
|
74176
73081
|
popActScope(prevActQueue, prevActScopeDepth);
|
|
74177
73082
|
0 < ReactSharedInternals.thrownErrors.length ? (error48 = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, reject(error48)) : reject(error48);
|
|
@@ -74187,11 +73092,11 @@ See https://react.dev/link/invalid-hook-call for tips about how to debug and fix
|
|
|
74187
73092
|
if (0 < ReactSharedInternals.thrownErrors.length)
|
|
74188
73093
|
throw callback = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, callback;
|
|
74189
73094
|
return {
|
|
74190
|
-
then: function(
|
|
73095
|
+
then: function(resolve13, reject) {
|
|
74191
73096
|
didAwaitActCall = true;
|
|
74192
73097
|
prevActScopeDepth === 0 ? (ReactSharedInternals.actQueue = queue, enqueueTask(function() {
|
|
74193
|
-
return recursivelyFlushAsyncActWork(returnValue$jscomp$0,
|
|
74194
|
-
})) :
|
|
73098
|
+
return recursivelyFlushAsyncActWork(returnValue$jscomp$0, resolve13, reject);
|
|
73099
|
+
})) : resolve13(returnValue$jscomp$0);
|
|
74195
73100
|
}
|
|
74196
73101
|
};
|
|
74197
73102
|
};
|
|
@@ -76672,8 +75577,8 @@ It can also happen if the client has a browser extension installed which messes
|
|
|
76672
75577
|
currentEntangledActionThenable = {
|
|
76673
75578
|
status: "pending",
|
|
76674
75579
|
value: undefined,
|
|
76675
|
-
then: function(
|
|
76676
|
-
entangledListeners.push(
|
|
75580
|
+
then: function(resolve13) {
|
|
75581
|
+
entangledListeners.push(resolve13);
|
|
76677
75582
|
}
|
|
76678
75583
|
};
|
|
76679
75584
|
}
|
|
@@ -76697,8 +75602,8 @@ It can also happen if the client has a browser extension installed which messes
|
|
|
76697
75602
|
status: "pending",
|
|
76698
75603
|
value: null,
|
|
76699
75604
|
reason: null,
|
|
76700
|
-
then: function(
|
|
76701
|
-
listeners.push(
|
|
75605
|
+
then: function(resolve13) {
|
|
75606
|
+
listeners.push(resolve13);
|
|
76702
75607
|
}
|
|
76703
75608
|
};
|
|
76704
75609
|
thenable.then(function() {
|
|
@@ -102680,14 +101585,14 @@ async function runScoutMonitorApp(options) {
|
|
|
102680
101585
|
}
|
|
102681
101586
|
const renderer = await createCliRenderer();
|
|
102682
101587
|
let closed = false;
|
|
102683
|
-
await new Promise((
|
|
101588
|
+
await new Promise((resolve13) => {
|
|
102684
101589
|
const close = () => {
|
|
102685
101590
|
if (closed) {
|
|
102686
101591
|
return;
|
|
102687
101592
|
}
|
|
102688
101593
|
closed = true;
|
|
102689
101594
|
renderer.destroy();
|
|
102690
|
-
|
|
101595
|
+
resolve13();
|
|
102691
101596
|
};
|
|
102692
101597
|
createRoot(renderer).render(/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ScoutMonitorApp, {
|
|
102693
101598
|
currentDirectory: options.currentDirectory,
|
|
@@ -102735,8 +101640,8 @@ var exports_up = {};
|
|
|
102735
101640
|
__export(exports_up, {
|
|
102736
101641
|
runUpCommand: () => runUpCommand
|
|
102737
101642
|
});
|
|
102738
|
-
import { existsSync as
|
|
102739
|
-
import { resolve as
|
|
101643
|
+
import { existsSync as existsSync19 } from "fs";
|
|
101644
|
+
import { resolve as resolve13 } from "path";
|
|
102740
101645
|
function looksLikePath(value) {
|
|
102741
101646
|
return value.includes("/") || value.startsWith(".") || value.startsWith("~");
|
|
102742
101647
|
}
|
|
@@ -102784,8 +101689,8 @@ async function runUpCommand(context, args) {
|
|
|
102784
101689
|
throw new ScoutCliError("usage: scout up <name|path> [--name <alias>] [--harness <claude|codex>]");
|
|
102785
101690
|
}
|
|
102786
101691
|
let projectPath;
|
|
102787
|
-
if (looksLikePath(target) ||
|
|
102788
|
-
projectPath =
|
|
101692
|
+
if (looksLikePath(target) || existsSync19(resolve13(target))) {
|
|
101693
|
+
projectPath = resolve13(target);
|
|
102789
101694
|
} else {
|
|
102790
101695
|
const resolved = await resolveLocalAgentByName(target);
|
|
102791
101696
|
if (!resolved) {
|
|
@@ -102823,10 +101728,9 @@ async function runWatchCommand(context, args) {
|
|
|
102823
101728
|
process.on("SIGINT", shutdown);
|
|
102824
101729
|
try {
|
|
102825
101730
|
if (context.output.mode === "plain") {
|
|
102826
|
-
context.stdout(`Watching ${options.channel?.trim() || "shared"}
|
|
101731
|
+
context.stdout(`Watching ${options.channel?.trim() || "shared"}`);
|
|
102827
101732
|
}
|
|
102828
101733
|
await watchScoutMessages({
|
|
102829
|
-
agentId: resolveScoutAgentName(options.agentName),
|
|
102830
101734
|
channel: options.channel,
|
|
102831
101735
|
signal: controller.signal,
|
|
102832
101736
|
onMessage(message) {
|
|
@@ -102861,6 +101765,49 @@ var init_who = __esm(async () => {
|
|
|
102861
101765
|
await init_service();
|
|
102862
101766
|
});
|
|
102863
101767
|
|
|
101768
|
+
// ../../apps/desktop/src/cli/commands/whoami.ts
|
|
101769
|
+
var exports_whoami = {};
|
|
101770
|
+
__export(exports_whoami, {
|
|
101771
|
+
runWhoAmICommand: () => runWhoAmICommand
|
|
101772
|
+
});
|
|
101773
|
+
async function loadScoutWhoAmIReport(context, currentDirectory) {
|
|
101774
|
+
const defaultSenderId = await resolveScoutSenderId(null, currentDirectory, context.env);
|
|
101775
|
+
const projectRoot = await findNearestProjectRoot(currentDirectory);
|
|
101776
|
+
return {
|
|
101777
|
+
defaultSenderId,
|
|
101778
|
+
envAgent: context.env.OPENSCOUT_AGENT?.trim() || null,
|
|
101779
|
+
currentDirectory,
|
|
101780
|
+
projectRoot,
|
|
101781
|
+
brokerUrl: resolveScoutBrokerUrl()
|
|
101782
|
+
};
|
|
101783
|
+
}
|
|
101784
|
+
function renderScoutWhoAmIReport(report) {
|
|
101785
|
+
const lines = [
|
|
101786
|
+
`Default Sender: ${report.defaultSenderId}`,
|
|
101787
|
+
`Current Directory: ${report.currentDirectory}`,
|
|
101788
|
+
`Broker: ${report.brokerUrl}`
|
|
101789
|
+
];
|
|
101790
|
+
if (report.projectRoot) {
|
|
101791
|
+
lines.splice(3, 0, `Project Root: ${report.projectRoot}`);
|
|
101792
|
+
}
|
|
101793
|
+
if (report.envAgent) {
|
|
101794
|
+
lines.splice(2, 0, `OPENSCOUT_AGENT: ${report.envAgent}`);
|
|
101795
|
+
}
|
|
101796
|
+
return lines.join(`
|
|
101797
|
+
`);
|
|
101798
|
+
}
|
|
101799
|
+
async function runWhoAmICommand(context, args) {
|
|
101800
|
+
const options = parseContextRootCommandOptions("whoami", args, defaultScoutContextDirectory(context));
|
|
101801
|
+
const report = await loadScoutWhoAmIReport(context, options.currentDirectory);
|
|
101802
|
+
context.output.writeValue(report, renderScoutWhoAmIReport);
|
|
101803
|
+
}
|
|
101804
|
+
var init_whoami = __esm(async () => {
|
|
101805
|
+
init_setup();
|
|
101806
|
+
init_context();
|
|
101807
|
+
init_options();
|
|
101808
|
+
await init_service();
|
|
101809
|
+
});
|
|
101810
|
+
|
|
102864
101811
|
// ../../apps/desktop/src/cli/argv.ts
|
|
102865
101812
|
function parseScoutArgv(argv) {
|
|
102866
101813
|
let command = null;
|
|
@@ -102920,6 +101867,10 @@ async function loadScoutCommandHandler(name) {
|
|
|
102920
101867
|
return (await init_enroll().then(() => exports_enroll)).runEnrollCommand;
|
|
102921
101868
|
case "env":
|
|
102922
101869
|
return (await init_env().then(() => exports_env)).runEnvCommand;
|
|
101870
|
+
case "latest":
|
|
101871
|
+
return (await init_latest().then(() => exports_latest)).runLatestCommand;
|
|
101872
|
+
case "menu":
|
|
101873
|
+
return (await Promise.resolve().then(() => (init_menu(), exports_menu))).runMenuCommand;
|
|
102923
101874
|
case "mesh":
|
|
102924
101875
|
return (await init_mesh().then(() => exports_mesh)).runMeshCommand;
|
|
102925
101876
|
case "pair":
|
|
@@ -102935,7 +101886,7 @@ async function loadScoutCommandHandler(name) {
|
|
|
102935
101886
|
case "server":
|
|
102936
101887
|
return (await Promise.resolve().then(() => (init_server2(), exports_server))).runServerCommand;
|
|
102937
101888
|
case "setup":
|
|
102938
|
-
return (await Promise.resolve().then(() => (init_setup2(),
|
|
101889
|
+
return (await Promise.resolve().then(() => (init_setup2(), exports_setup))).runSetupCommand;
|
|
102939
101890
|
case "speak":
|
|
102940
101891
|
return (await init_speak().then(() => exports_speak)).runSpeakCommand;
|
|
102941
101892
|
case "tui":
|
|
@@ -102946,6 +101897,8 @@ async function loadScoutCommandHandler(name) {
|
|
|
102946
101897
|
return (await init_watch().then(() => exports_watch)).runWatchCommand;
|
|
102947
101898
|
case "who":
|
|
102948
101899
|
return (await init_who().then(() => exports_who)).runWhoCommand;
|
|
101900
|
+
case "whoami":
|
|
101901
|
+
return (await init_whoami().then(() => exports_whoami)).runWhoAmICommand;
|
|
102949
101902
|
}
|
|
102950
101903
|
}
|
|
102951
101904
|
|
|
@@ -102957,18 +101910,21 @@ var SCOUT_COMMANDS = [
|
|
|
102957
101910
|
{ name: "doctor", summary: "Show broker health and project inventory" },
|
|
102958
101911
|
{ name: "runtimes", summary: "Show harness catalog and readiness" },
|
|
102959
101912
|
{ name: "env", summary: "Show executable and agent identity context" },
|
|
101913
|
+
{ name: "whoami", summary: "Show your current Scout identity defaults" },
|
|
102960
101914
|
{ name: "send", summary: "Post a broker-backed message" },
|
|
102961
101915
|
{ name: "speak", summary: "Send and speak aloud via TTS" },
|
|
102962
101916
|
{ name: "ask", summary: "Ask an agent and wait for the answer" },
|
|
102963
101917
|
{ name: "card", summary: "Create a dedicated relay agent card" },
|
|
102964
101918
|
{ name: "watch", summary: "Stream broker messages" },
|
|
102965
101919
|
{ name: "who", summary: "List agents and last activity" },
|
|
101920
|
+
{ name: "latest", summary: "Show the latest Scout activity" },
|
|
102966
101921
|
{ name: "enroll", summary: "Generate enrollment prompt" },
|
|
102967
101922
|
{ name: "broadcast", summary: "Send to all routable agents" },
|
|
102968
101923
|
{ name: "up", summary: "Spawn a local agent for a project" },
|
|
102969
101924
|
{ name: "down", summary: "Stop one or all local agents" },
|
|
102970
101925
|
{ name: "ps", summary: "List configured local agents" },
|
|
102971
101926
|
{ name: "restart", summary: "Restart configured local agents" },
|
|
101927
|
+
{ name: "menu", summary: "Launch the OpenScout macOS menu bar app" },
|
|
102972
101928
|
{ name: "config", summary: "View or set user config (name, etc.)" },
|
|
102973
101929
|
{ name: "mesh", summary: "Mesh status and diagnostics" },
|
|
102974
101930
|
{ name: "pair", summary: "Pair a companion device via QR" },
|
|
@@ -103021,6 +101977,13 @@ function renderScoutHelp(version2 = "0.2.18") {
|
|
|
103021
101977
|
" scout hey @agent can you review this?",
|
|
103022
101978
|
" scout @agent.harness:codex use the Codex-backed one",
|
|
103023
101979
|
"",
|
|
101980
|
+
"Operator loop:",
|
|
101981
|
+
" scout whoami",
|
|
101982
|
+
" scout who",
|
|
101983
|
+
" scout latest",
|
|
101984
|
+
" scout menu",
|
|
101985
|
+
" scout server open",
|
|
101986
|
+
"",
|
|
103024
101987
|
"Addressing:",
|
|
103025
101988
|
" @name short form; requires exactly one live match",
|
|
103026
101989
|
" @name.harness:<codex|claude|...> pin a specific harness (alias: runtime:)",
|