@openscout/scout 0.2.61 → 0.2.62
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 +29 -0
- package/dist/client/assets/{arc.es-DgeMPL-I.js → arc.es-nBIiEfYv.js} +1 -1
- package/dist/client/assets/index-BdwfgbIm.js +140 -0
- package/dist/client/assets/index-tcdw22Rl.css +1 -0
- package/dist/client/index.html +3 -2
- package/dist/main.mjs +1432 -922
- package/dist/pair-supervisor.mjs +671 -304
- package/dist/scout-control-plane-web.mjs +9353 -8304
- package/package.json +2 -2
- package/dist/client/assets/index-25TJx0iN.js +0 -140
- package/dist/client/assets/index-B1kglsyi.css +0 -1
package/dist/main.mjs
CHANGED
|
@@ -118,6 +118,15 @@ function parseFlagValue(args, index, flag) {
|
|
|
118
118
|
}
|
|
119
119
|
missingFlagValue(flag);
|
|
120
120
|
}
|
|
121
|
+
function flagNameFor(current, flagNames) {
|
|
122
|
+
return flagNames.find((flag) => current === flag || current.startsWith(`${flag}=`)) ?? null;
|
|
123
|
+
}
|
|
124
|
+
function resolveInputFilePath(currentDirectory, filePath) {
|
|
125
|
+
return resolve2(currentDirectory, filePath);
|
|
126
|
+
}
|
|
127
|
+
function rejectMixedBodySources(kind) {
|
|
128
|
+
throw new ScoutCliError(kind === "message" ? "provide either an inline message or --message-file/--body-file, not both" : "provide either an inline question or --prompt-file/--body-file, not both");
|
|
129
|
+
}
|
|
121
130
|
function parseContextRootPrefix(args, defaultCurrentDirectory) {
|
|
122
131
|
let currentDirectory = defaultCurrentDirectory;
|
|
123
132
|
const rest = [];
|
|
@@ -184,6 +193,7 @@ function parseSendCommandOptions(args, defaultCurrentDirectory) {
|
|
|
184
193
|
let channel;
|
|
185
194
|
let shouldSpeak = false;
|
|
186
195
|
let harness;
|
|
196
|
+
let messageFile;
|
|
187
197
|
const messageParts = [];
|
|
188
198
|
for (let index = 0;index < parsed.args.length; index += 1) {
|
|
189
199
|
const current = parsed.args[index] ?? "";
|
|
@@ -209,10 +219,23 @@ function parseSendCommandOptions(args, defaultCurrentDirectory) {
|
|
|
209
219
|
shouldSpeak = true;
|
|
210
220
|
continue;
|
|
211
221
|
}
|
|
222
|
+
const fileFlag = flagNameFor(current, ["--message-file", "--body-file"]);
|
|
223
|
+
if (fileFlag) {
|
|
224
|
+
if (messageFile) {
|
|
225
|
+
throw new ScoutCliError("message file was provided more than once");
|
|
226
|
+
}
|
|
227
|
+
const value = parseFlagValue(parsed.args, index, fileFlag);
|
|
228
|
+
messageFile = resolveInputFilePath(parsed.currentDirectory, value.value);
|
|
229
|
+
index = value.nextIndex;
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
212
232
|
messageParts.push(current);
|
|
213
233
|
}
|
|
214
234
|
const message = messageParts.join(" ").trim();
|
|
215
|
-
if (
|
|
235
|
+
if (message && messageFile) {
|
|
236
|
+
rejectMixedBodySources("message");
|
|
237
|
+
}
|
|
238
|
+
if (!message && !messageFile) {
|
|
216
239
|
throw new ScoutCliError("no message provided");
|
|
217
240
|
}
|
|
218
241
|
return {
|
|
@@ -222,7 +245,8 @@ function parseSendCommandOptions(args, defaultCurrentDirectory) {
|
|
|
222
245
|
channel,
|
|
223
246
|
shouldSpeak,
|
|
224
247
|
harness,
|
|
225
|
-
message
|
|
248
|
+
message,
|
|
249
|
+
messageFile
|
|
226
250
|
};
|
|
227
251
|
}
|
|
228
252
|
function parseAskCommandOptions(args, defaultCurrentDirectory) {
|
|
@@ -232,6 +256,7 @@ function parseAskCommandOptions(args, defaultCurrentDirectory) {
|
|
|
232
256
|
let channel;
|
|
233
257
|
let harness;
|
|
234
258
|
let timeoutSeconds;
|
|
259
|
+
let promptFile;
|
|
235
260
|
const messageParts = [];
|
|
236
261
|
for (let index = 0;index < parsed.args.length; index += 1) {
|
|
237
262
|
const current = parsed.args[index] ?? "";
|
|
@@ -269,13 +294,26 @@ function parseAskCommandOptions(args, defaultCurrentDirectory) {
|
|
|
269
294
|
index = value.nextIndex;
|
|
270
295
|
continue;
|
|
271
296
|
}
|
|
297
|
+
const fileFlag = flagNameFor(current, ["--prompt-file", "--body-file"]);
|
|
298
|
+
if (fileFlag) {
|
|
299
|
+
if (promptFile) {
|
|
300
|
+
throw new ScoutCliError("prompt file was provided more than once");
|
|
301
|
+
}
|
|
302
|
+
const value = parseFlagValue(parsed.args, index, fileFlag);
|
|
303
|
+
promptFile = resolveInputFilePath(parsed.currentDirectory, value.value);
|
|
304
|
+
index = value.nextIndex;
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
272
307
|
messageParts.push(current);
|
|
273
308
|
}
|
|
274
309
|
const message = messageParts.join(" ").trim();
|
|
275
310
|
if (!targetLabel) {
|
|
276
311
|
throw new ScoutCliError("--to <name> is required");
|
|
277
312
|
}
|
|
278
|
-
if (
|
|
313
|
+
if (message && promptFile) {
|
|
314
|
+
rejectMixedBodySources("question");
|
|
315
|
+
}
|
|
316
|
+
if (!message && !promptFile) {
|
|
279
317
|
throw new ScoutCliError("no question provided");
|
|
280
318
|
}
|
|
281
319
|
return {
|
|
@@ -286,7 +324,8 @@ function parseAskCommandOptions(args, defaultCurrentDirectory) {
|
|
|
286
324
|
channel,
|
|
287
325
|
harness,
|
|
288
326
|
timeoutSeconds,
|
|
289
|
-
message
|
|
327
|
+
message,
|
|
328
|
+
promptFile
|
|
290
329
|
};
|
|
291
330
|
}
|
|
292
331
|
function parseImplicitAskCommandOptions(args, defaultCurrentDirectory) {
|
|
@@ -295,6 +334,7 @@ function parseImplicitAskCommandOptions(args, defaultCurrentDirectory) {
|
|
|
295
334
|
let channel;
|
|
296
335
|
let harness;
|
|
297
336
|
let timeoutSeconds;
|
|
337
|
+
let promptFile;
|
|
298
338
|
const messageParts = [];
|
|
299
339
|
for (let index = 0;index < parsed.args.length; index += 1) {
|
|
300
340
|
const current = parsed.args[index] ?? "";
|
|
@@ -326,6 +366,16 @@ function parseImplicitAskCommandOptions(args, defaultCurrentDirectory) {
|
|
|
326
366
|
index = value.nextIndex;
|
|
327
367
|
continue;
|
|
328
368
|
}
|
|
369
|
+
const fileFlag = flagNameFor(current, ["--prompt-file", "--body-file"]);
|
|
370
|
+
if (fileFlag) {
|
|
371
|
+
if (promptFile) {
|
|
372
|
+
throw new ScoutCliError("prompt file was provided more than once");
|
|
373
|
+
}
|
|
374
|
+
const value = parseFlagValue(parsed.args, index, fileFlag);
|
|
375
|
+
promptFile = resolveInputFilePath(parsed.currentDirectory, value.value);
|
|
376
|
+
index = value.nextIndex;
|
|
377
|
+
continue;
|
|
378
|
+
}
|
|
329
379
|
messageParts.push(current);
|
|
330
380
|
}
|
|
331
381
|
const input = messageParts.join(" ").trim();
|
|
@@ -341,7 +391,10 @@ function parseImplicitAskCommandOptions(args, defaultCurrentDirectory) {
|
|
|
341
391
|
}
|
|
342
392
|
const [target] = mentions;
|
|
343
393
|
const message = stripMention(input, target);
|
|
344
|
-
if (
|
|
394
|
+
if (message && promptFile) {
|
|
395
|
+
rejectMixedBodySources("question");
|
|
396
|
+
}
|
|
397
|
+
if (!message && !promptFile) {
|
|
345
398
|
throw new ScoutCliError("no question provided");
|
|
346
399
|
}
|
|
347
400
|
return {
|
|
@@ -352,7 +405,8 @@ function parseImplicitAskCommandOptions(args, defaultCurrentDirectory) {
|
|
|
352
405
|
channel,
|
|
353
406
|
harness,
|
|
354
407
|
timeoutSeconds,
|
|
355
|
-
message
|
|
408
|
+
message,
|
|
409
|
+
promptFile
|
|
356
410
|
};
|
|
357
411
|
}
|
|
358
412
|
function parseWatchCommandOptions(args, defaultCurrentDirectory) {
|
|
@@ -581,6 +635,32 @@ var init_options = __esm(() => {
|
|
|
581
635
|
SCOUT_MENTION_PATTERN = /(^|[\s([{'"`])@([A-Za-z0-9._:-]+)(?=$|[\s)\]}",.!?:;'"`])/g;
|
|
582
636
|
});
|
|
583
637
|
|
|
638
|
+
// ../../apps/desktop/src/cli/input-file.ts
|
|
639
|
+
import { readFile } from "fs/promises";
|
|
640
|
+
async function readCliInputFile(filePath, label) {
|
|
641
|
+
let body;
|
|
642
|
+
try {
|
|
643
|
+
body = await readFile(filePath, "utf8");
|
|
644
|
+
} catch (error) {
|
|
645
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
646
|
+
throw new ScoutCliError(`could not read ${label} file ${filePath}: ${detail}`);
|
|
647
|
+
}
|
|
648
|
+
const normalized = body.replace(/^\uFEFF/, "");
|
|
649
|
+
if (!normalized.trim()) {
|
|
650
|
+
throw new ScoutCliError(`${label} file is empty: ${filePath}`);
|
|
651
|
+
}
|
|
652
|
+
return normalized;
|
|
653
|
+
}
|
|
654
|
+
async function resolvePromptBody(input) {
|
|
655
|
+
return input.promptFile ? readCliInputFile(input.promptFile, "prompt") : input.message;
|
|
656
|
+
}
|
|
657
|
+
async function resolveMessageBody(input) {
|
|
658
|
+
return input.messageFile ? readCliInputFile(input.messageFile, "message") : input.message;
|
|
659
|
+
}
|
|
660
|
+
var init_input_file = __esm(() => {
|
|
661
|
+
init_errors();
|
|
662
|
+
});
|
|
663
|
+
|
|
584
664
|
// ../protocol/dist/common.js
|
|
585
665
|
var init_common = () => {};
|
|
586
666
|
|
|
@@ -996,6 +1076,9 @@ var init_invocations = () => {};
|
|
|
996
1076
|
// ../protocol/dist/scout-dispatch.js
|
|
997
1077
|
var init_scout_dispatch = () => {};
|
|
998
1078
|
|
|
1079
|
+
// ../protocol/dist/scout-delivery.js
|
|
1080
|
+
var init_scout_delivery = () => {};
|
|
1081
|
+
|
|
999
1082
|
// ../protocol/dist/deliveries.js
|
|
1000
1083
|
var init_deliveries = () => {};
|
|
1001
1084
|
|
|
@@ -1020,6 +1103,7 @@ var init_dist = __esm(() => {
|
|
|
1020
1103
|
init_messages();
|
|
1021
1104
|
init_invocations();
|
|
1022
1105
|
init_scout_dispatch();
|
|
1106
|
+
init_scout_delivery();
|
|
1023
1107
|
init_deliveries();
|
|
1024
1108
|
init_transports();
|
|
1025
1109
|
init_events();
|
|
@@ -2064,7 +2148,7 @@ var init_support_paths = () => {};
|
|
|
2064
2148
|
// ../runtime/src/harness-catalog.ts
|
|
2065
2149
|
import { execFileSync } from "child_process";
|
|
2066
2150
|
import { existsSync as existsSync2, statSync } from "fs";
|
|
2067
|
-
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
2151
|
+
import { mkdir, readFile as readFile2, writeFile } from "fs/promises";
|
|
2068
2152
|
import { dirname, join as join2 } from "path";
|
|
2069
2153
|
function expandHomePath(value) {
|
|
2070
2154
|
if (value === "~")
|
|
@@ -2295,7 +2379,7 @@ function evaluateHarnessReadiness(entry, options = {}) {
|
|
|
2295
2379
|
}
|
|
2296
2380
|
async function readHarnessCatalogOverrides(overridePath = resolveOpenScoutSupportPaths().harnessCatalogPath) {
|
|
2297
2381
|
try {
|
|
2298
|
-
const raw = JSON.parse(await
|
|
2382
|
+
const raw = JSON.parse(await readFile2(overridePath, "utf8"));
|
|
2299
2383
|
return raw.entries ?? {};
|
|
2300
2384
|
} catch {
|
|
2301
2385
|
return {};
|
|
@@ -2422,7 +2506,7 @@ var init_harness_catalog = __esm(() => {
|
|
|
2422
2506
|
});
|
|
2423
2507
|
|
|
2424
2508
|
// ../runtime/src/user-project-hints.ts
|
|
2425
|
-
import { readdir, readFile as
|
|
2509
|
+
import { readdir, readFile as readFile3, stat } from "fs/promises";
|
|
2426
2510
|
import { homedir as homedir2 } from "os";
|
|
2427
2511
|
import { dirname as dirname2, join as join3, resolve as resolve3 } from "path";
|
|
2428
2512
|
import { fileURLToPath } from "url";
|
|
@@ -2547,7 +2631,7 @@ async function appendCodexHistoryPaths(home, roots) {
|
|
|
2547
2631
|
}
|
|
2548
2632
|
let body;
|
|
2549
2633
|
try {
|
|
2550
|
-
body = await
|
|
2634
|
+
body = await readFile3(filePath, "utf8");
|
|
2551
2635
|
} catch {
|
|
2552
2636
|
continue;
|
|
2553
2637
|
}
|
|
@@ -2586,7 +2670,7 @@ async function appendCursorWorkspacePaths(home, roots) {
|
|
|
2586
2670
|
const workspaceJsonPath = join3(base, id, "workspace.json");
|
|
2587
2671
|
let raw;
|
|
2588
2672
|
try {
|
|
2589
|
-
raw = await
|
|
2673
|
+
raw = await readFile3(workspaceJsonPath, "utf8");
|
|
2590
2674
|
} catch {
|
|
2591
2675
|
continue;
|
|
2592
2676
|
}
|
|
@@ -2617,7 +2701,7 @@ async function appendCursorWorkspacePaths(home, roots) {
|
|
|
2617
2701
|
if (!wsStat.isFile()) {
|
|
2618
2702
|
continue;
|
|
2619
2703
|
}
|
|
2620
|
-
const wsRaw = await
|
|
2704
|
+
const wsRaw = await readFile3(wsFile, "utf8");
|
|
2621
2705
|
const wsDoc = JSON.parse(wsRaw);
|
|
2622
2706
|
const wsDir = dirname2(wsFile);
|
|
2623
2707
|
for (const f of wsDoc.folders ?? []) {
|
|
@@ -2687,7 +2771,7 @@ async function appendClaudeSessionPaths(home, roots) {
|
|
|
2687
2771
|
seenFiles += 1;
|
|
2688
2772
|
let body;
|
|
2689
2773
|
try {
|
|
2690
|
-
body = await
|
|
2774
|
+
body = await readFile3(sessionPath, "utf8");
|
|
2691
2775
|
} catch {
|
|
2692
2776
|
continue;
|
|
2693
2777
|
}
|
|
@@ -2749,7 +2833,7 @@ var init_user_project_hints = __esm(() => {
|
|
|
2749
2833
|
// ../runtime/src/setup.ts
|
|
2750
2834
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
2751
2835
|
import { existsSync as existsSync3, readFileSync } from "fs";
|
|
2752
|
-
import { access, mkdir as mkdir2, readdir as readdir2, readFile as
|
|
2836
|
+
import { access, mkdir as mkdir2, readdir as readdir2, readFile as readFile4, realpath, rm, stat as stat2, writeFile as writeFile2 } from "fs/promises";
|
|
2753
2837
|
import { homedir as homedir3, hostname, userInfo } from "os";
|
|
2754
2838
|
import { basename, dirname as dirname3, isAbsolute, join as join4, relative, resolve as resolve4 } from "path";
|
|
2755
2839
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
@@ -3206,7 +3290,7 @@ async function isDirectory(filePath) {
|
|
|
3206
3290
|
}
|
|
3207
3291
|
async function readJsonFile(filePath) {
|
|
3208
3292
|
try {
|
|
3209
|
-
return JSON.parse(await
|
|
3293
|
+
return JSON.parse(await readFile4(filePath, "utf8"));
|
|
3210
3294
|
} catch {
|
|
3211
3295
|
return null;
|
|
3212
3296
|
}
|
|
@@ -3352,7 +3436,7 @@ async function readCodexEnvironmentImport(projectRoot) {
|
|
|
3352
3436
|
const sourcePath = codexEnvironmentPath(projectRoot);
|
|
3353
3437
|
let body;
|
|
3354
3438
|
try {
|
|
3355
|
-
body = await
|
|
3439
|
+
body = await readFile4(sourcePath, "utf8");
|
|
3356
3440
|
} catch {
|
|
3357
3441
|
return null;
|
|
3358
3442
|
}
|
|
@@ -3398,7 +3482,7 @@ async function readClaudeProjectImport(projectRoot) {
|
|
|
3398
3482
|
const sessionPath = join4(sourcePath, entry);
|
|
3399
3483
|
let body;
|
|
3400
3484
|
try {
|
|
3401
|
-
body = await
|
|
3485
|
+
body = await readFile4(sessionPath, "utf8");
|
|
3402
3486
|
} catch {
|
|
3403
3487
|
continue;
|
|
3404
3488
|
}
|
|
@@ -3492,7 +3576,7 @@ async function ensureProjectConfigIgnored(projectRoot) {
|
|
|
3492
3576
|
const comment = "# OpenScout local state";
|
|
3493
3577
|
let current = "";
|
|
3494
3578
|
try {
|
|
3495
|
-
current = await
|
|
3579
|
+
current = await readFile4(gitignorePath, "utf8");
|
|
3496
3580
|
} catch {
|
|
3497
3581
|
current = "";
|
|
3498
3582
|
}
|
|
@@ -3653,6 +3737,35 @@ async function readOpenScoutSettings(options = {}) {
|
|
|
3653
3737
|
legacyAgents
|
|
3654
3738
|
});
|
|
3655
3739
|
}
|
|
3740
|
+
function resolveOpenScoutSetupContextRoot(options = {}) {
|
|
3741
|
+
const env = options.env ?? process.env;
|
|
3742
|
+
const explicit = env.OPENSCOUT_SETUP_CWD?.trim();
|
|
3743
|
+
if (explicit) {
|
|
3744
|
+
return normalizePath(explicit);
|
|
3745
|
+
}
|
|
3746
|
+
const home = env.HOME?.trim() || homedir3();
|
|
3747
|
+
const supportDirectory = env.OPENSCOUT_SUPPORT_DIRECTORY?.trim() || join4(home, "Library", "Application Support", "OpenScout");
|
|
3748
|
+
const settingsPath = join4(supportDirectory, "settings.json");
|
|
3749
|
+
if (existsSync3(settingsPath)) {
|
|
3750
|
+
try {
|
|
3751
|
+
const raw = JSON.parse(readFileSync(settingsPath, "utf8"));
|
|
3752
|
+
const discovery = raw.discovery;
|
|
3753
|
+
if (typeof discovery?.contextRoot === "string" && discovery.contextRoot.trim()) {
|
|
3754
|
+
return normalizePath(discovery.contextRoot);
|
|
3755
|
+
}
|
|
3756
|
+
if (Array.isArray(discovery?.workspaceRoots)) {
|
|
3757
|
+
const workspaceRoot = discovery.workspaceRoots.find((entry) => typeof entry === "string" && entry.trim().length > 0);
|
|
3758
|
+
if (workspaceRoot) {
|
|
3759
|
+
return normalizePath(workspaceRoot);
|
|
3760
|
+
}
|
|
3761
|
+
}
|
|
3762
|
+
} catch {}
|
|
3763
|
+
}
|
|
3764
|
+
if (options.fallbackDirectory?.trim()) {
|
|
3765
|
+
return normalizePath(options.fallbackDirectory);
|
|
3766
|
+
}
|
|
3767
|
+
return normalizePath(process.cwd());
|
|
3768
|
+
}
|
|
3656
3769
|
async function writeOpenScoutSettings(settings, options = {}) {
|
|
3657
3770
|
ensureOpenScoutCleanSlateSync();
|
|
3658
3771
|
const current = await readOpenScoutSettings(options);
|
|
@@ -3715,7 +3828,7 @@ async function installScoutSkillToHarnesses() {
|
|
|
3715
3828
|
if (!source) {
|
|
3716
3829
|
return { source: null, entries: [] };
|
|
3717
3830
|
}
|
|
3718
|
-
const content = await
|
|
3831
|
+
const content = await readFile4(source, "utf8");
|
|
3719
3832
|
const entries = [];
|
|
3720
3833
|
for (const harness of MANAGED_AGENT_HARNESSES) {
|
|
3721
3834
|
const target = SCOUT_SKILL_INSTALL_PATHS[harness];
|
|
@@ -4595,7 +4708,7 @@ function buildManagedAgentShellExports(options) {
|
|
|
4595
4708
|
// ../runtime/src/claude-stream-json.ts
|
|
4596
4709
|
import { randomUUID } from "crypto";
|
|
4597
4710
|
import { spawn } from "child_process";
|
|
4598
|
-
import { appendFile, mkdir as mkdir3, readFile as
|
|
4711
|
+
import { appendFile, mkdir as mkdir3, readFile as readFile5, writeFile as writeFile3 } from "fs/promises";
|
|
4599
4712
|
import { existsSync as existsSync4, readFileSync as readFileSync2 } from "fs";
|
|
4600
4713
|
import { join as join5 } from "path";
|
|
4601
4714
|
function resolveClaudeStreamJsonOutput(result, fallbackParts) {
|
|
@@ -5061,6 +5174,9 @@ function normalizeApprovalRequest(session, turnId, block) {
|
|
|
5061
5174
|
};
|
|
5062
5175
|
}
|
|
5063
5176
|
|
|
5177
|
+
// ../agent-sessions/src/protocol/cost.ts
|
|
5178
|
+
var init_cost = () => {};
|
|
5179
|
+
|
|
5064
5180
|
// ../agent-sessions/src/state.ts
|
|
5065
5181
|
function normalizeTrackedTimestamp(value) {
|
|
5066
5182
|
if (value == null) {
|
|
@@ -5607,6 +5723,15 @@ function stringifyUnknown(value) {
|
|
|
5607
5723
|
return String(value);
|
|
5608
5724
|
}
|
|
5609
5725
|
}
|
|
5726
|
+
function isRecord(value) {
|
|
5727
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
5728
|
+
}
|
|
5729
|
+
function maybeString(value) {
|
|
5730
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
|
|
5731
|
+
}
|
|
5732
|
+
function maybeNumber(value) {
|
|
5733
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
5734
|
+
}
|
|
5610
5735
|
function renderToolResultContent(content) {
|
|
5611
5736
|
if (typeof content === "string") {
|
|
5612
5737
|
return content;
|
|
@@ -5663,6 +5788,7 @@ class ClaudeCodeHistoryParser {
|
|
|
5663
5788
|
blockById = new Map;
|
|
5664
5789
|
activeStreamBlocks = new Map;
|
|
5665
5790
|
sawStreamTextThisTurn = false;
|
|
5791
|
+
assistantUsageByMessageId = new Map;
|
|
5666
5792
|
constructor(session, baseTimestampMs) {
|
|
5667
5793
|
this.session = session;
|
|
5668
5794
|
this.baseTimestampMs = baseTimestampMs;
|
|
@@ -5672,6 +5798,7 @@ class ClaudeCodeHistoryParser {
|
|
|
5672
5798
|
let parsedLineCount = 0;
|
|
5673
5799
|
let skippedLineCount = 0;
|
|
5674
5800
|
let lineCount = 0;
|
|
5801
|
+
let lastCapturedAt = this.baseTimestampMs;
|
|
5675
5802
|
for (let index = 0;index < lines.length; index += 1) {
|
|
5676
5803
|
const rawLine = lines[index];
|
|
5677
5804
|
const trimmed = rawLine.trim();
|
|
@@ -5692,12 +5819,19 @@ class ClaudeCodeHistoryParser {
|
|
|
5692
5819
|
continue;
|
|
5693
5820
|
}
|
|
5694
5821
|
const capturedAt = extractRecordTimestamp(record) ?? this.baseTimestampMs + index;
|
|
5822
|
+
lastCapturedAt = capturedAt;
|
|
5695
5823
|
if (this.handleRecord(record, capturedAt)) {
|
|
5696
5824
|
parsedLineCount += 1;
|
|
5697
5825
|
} else {
|
|
5698
5826
|
skippedLineCount += 1;
|
|
5699
5827
|
}
|
|
5700
5828
|
}
|
|
5829
|
+
if (this.persistObserveUsageMetadata()) {
|
|
5830
|
+
this.emitEvent(lastCapturedAt, {
|
|
5831
|
+
event: "session:update",
|
|
5832
|
+
session: { ...this.session }
|
|
5833
|
+
});
|
|
5834
|
+
}
|
|
5701
5835
|
return {
|
|
5702
5836
|
events: this.events,
|
|
5703
5837
|
lineCount,
|
|
@@ -5706,6 +5840,7 @@ class ClaudeCodeHistoryParser {
|
|
|
5706
5840
|
};
|
|
5707
5841
|
}
|
|
5708
5842
|
handleRecord(record, capturedAt) {
|
|
5843
|
+
this.captureRecordMetadata(record);
|
|
5709
5844
|
const type = typeof record.type === "string" ? record.type : null;
|
|
5710
5845
|
if (!type) {
|
|
5711
5846
|
return false;
|
|
@@ -5715,7 +5850,7 @@ class ClaudeCodeHistoryParser {
|
|
|
5715
5850
|
this.handleSystem(record, capturedAt);
|
|
5716
5851
|
return true;
|
|
5717
5852
|
case "user":
|
|
5718
|
-
this.
|
|
5853
|
+
this.handleUser(record, capturedAt);
|
|
5719
5854
|
return true;
|
|
5720
5855
|
case "assistant":
|
|
5721
5856
|
this.handleAssistant(record, capturedAt);
|
|
@@ -5739,6 +5874,130 @@ class ClaudeCodeHistoryParser {
|
|
|
5739
5874
|
return false;
|
|
5740
5875
|
}
|
|
5741
5876
|
}
|
|
5877
|
+
captureRecordMetadata(record) {
|
|
5878
|
+
const runtime = this.ensureObserveMetaRecord("observeRuntime");
|
|
5879
|
+
this.assignObserveString(runtime, "entrypoint", record.entrypoint);
|
|
5880
|
+
this.assignObserveString(runtime, "cliVersion", record.version);
|
|
5881
|
+
this.assignObserveString(runtime, "gitBranch", record.gitBranch);
|
|
5882
|
+
this.assignObserveString(runtime, "permissionMode", record.permissionMode);
|
|
5883
|
+
this.assignObserveString(runtime, "userType", record.userType);
|
|
5884
|
+
const recordCwd = maybeString(record.cwd);
|
|
5885
|
+
if (recordCwd && !this.session.cwd) {
|
|
5886
|
+
this.session.cwd = recordCwd;
|
|
5887
|
+
}
|
|
5888
|
+
const message = isRecord(record.message) ? record.message : null;
|
|
5889
|
+
const model = maybeString(message?.model);
|
|
5890
|
+
if (model && !this.session.model) {
|
|
5891
|
+
this.session.model = model;
|
|
5892
|
+
}
|
|
5893
|
+
const usage = this.readClaudeUsageEntry(record);
|
|
5894
|
+
if (!usage) {
|
|
5895
|
+
return;
|
|
5896
|
+
}
|
|
5897
|
+
const messageId = maybeString(message?.id) ?? maybeString(record.requestId) ?? maybeString(record.uuid);
|
|
5898
|
+
if (!messageId) {
|
|
5899
|
+
return;
|
|
5900
|
+
}
|
|
5901
|
+
this.assistantUsageByMessageId.set(messageId, usage);
|
|
5902
|
+
}
|
|
5903
|
+
readClaudeUsageEntry(record) {
|
|
5904
|
+
const type = maybeString(record.type);
|
|
5905
|
+
const message = isRecord(record.message) ? record.message : null;
|
|
5906
|
+
const role = maybeString(message?.role);
|
|
5907
|
+
if (type !== "assistant" && role !== "assistant") {
|
|
5908
|
+
return null;
|
|
5909
|
+
}
|
|
5910
|
+
const usage = isRecord(message?.usage) ? message.usage : null;
|
|
5911
|
+
const serverToolUse = isRecord(usage?.server_tool_use) ? usage.server_tool_use : null;
|
|
5912
|
+
const entry = {
|
|
5913
|
+
inputTokens: maybeNumber(usage?.input_tokens) ?? 0,
|
|
5914
|
+
outputTokens: maybeNumber(usage?.output_tokens) ?? 0,
|
|
5915
|
+
cacheReadInputTokens: maybeNumber(usage?.cache_read_input_tokens) ?? 0,
|
|
5916
|
+
cacheCreationInputTokens: maybeNumber(usage?.cache_creation_input_tokens) ?? 0,
|
|
5917
|
+
webSearchRequests: maybeNumber(serverToolUse?.web_search_requests) ?? 0,
|
|
5918
|
+
webFetchRequests: maybeNumber(serverToolUse?.web_fetch_requests) ?? 0,
|
|
5919
|
+
...maybeString(message?.service_tier) ? { serviceTier: maybeString(message?.service_tier) } : {},
|
|
5920
|
+
...maybeString(message?.speed) ? { speed: maybeString(message?.speed) } : {}
|
|
5921
|
+
};
|
|
5922
|
+
const hasUsage = entry.inputTokens > 0 || entry.outputTokens > 0 || entry.cacheReadInputTokens > 0 || entry.cacheCreationInputTokens > 0 || entry.webSearchRequests > 0 || entry.webFetchRequests > 0 || Boolean(entry.serviceTier) || Boolean(entry.speed);
|
|
5923
|
+
return hasUsage ? entry : null;
|
|
5924
|
+
}
|
|
5925
|
+
persistObserveUsageMetadata() {
|
|
5926
|
+
if (this.assistantUsageByMessageId.size === 0) {
|
|
5927
|
+
return false;
|
|
5928
|
+
}
|
|
5929
|
+
const usage = this.ensureObserveMetaRecord("observeUsage");
|
|
5930
|
+
let inputTokens = 0;
|
|
5931
|
+
let outputTokens = 0;
|
|
5932
|
+
let cacheReadInputTokens = 0;
|
|
5933
|
+
let cacheCreationInputTokens = 0;
|
|
5934
|
+
let webSearchRequests = 0;
|
|
5935
|
+
let webFetchRequests = 0;
|
|
5936
|
+
let serviceTier;
|
|
5937
|
+
let speed;
|
|
5938
|
+
for (const entry of this.assistantUsageByMessageId.values()) {
|
|
5939
|
+
inputTokens += entry.inputTokens;
|
|
5940
|
+
outputTokens += entry.outputTokens;
|
|
5941
|
+
cacheReadInputTokens += entry.cacheReadInputTokens;
|
|
5942
|
+
cacheCreationInputTokens += entry.cacheCreationInputTokens;
|
|
5943
|
+
webSearchRequests += entry.webSearchRequests;
|
|
5944
|
+
webFetchRequests += entry.webFetchRequests;
|
|
5945
|
+
if (entry.serviceTier) {
|
|
5946
|
+
serviceTier = entry.serviceTier;
|
|
5947
|
+
}
|
|
5948
|
+
if (entry.speed) {
|
|
5949
|
+
speed = entry.speed;
|
|
5950
|
+
}
|
|
5951
|
+
}
|
|
5952
|
+
let changed = false;
|
|
5953
|
+
const assignNumber = (key, value) => {
|
|
5954
|
+
if (usage[key] !== value) {
|
|
5955
|
+
usage[key] = value;
|
|
5956
|
+
changed = true;
|
|
5957
|
+
}
|
|
5958
|
+
};
|
|
5959
|
+
const assignString = (key, value) => {
|
|
5960
|
+
if (usage[key] !== value) {
|
|
5961
|
+
usage[key] = value;
|
|
5962
|
+
changed = true;
|
|
5963
|
+
}
|
|
5964
|
+
};
|
|
5965
|
+
assignNumber("assistantMessages", this.assistantUsageByMessageId.size);
|
|
5966
|
+
if (inputTokens > 0)
|
|
5967
|
+
assignNumber("inputTokens", inputTokens);
|
|
5968
|
+
if (outputTokens > 0)
|
|
5969
|
+
assignNumber("outputTokens", outputTokens);
|
|
5970
|
+
if (cacheReadInputTokens > 0)
|
|
5971
|
+
assignNumber("cacheReadInputTokens", cacheReadInputTokens);
|
|
5972
|
+
if (cacheCreationInputTokens > 0)
|
|
5973
|
+
assignNumber("cacheCreationInputTokens", cacheCreationInputTokens);
|
|
5974
|
+
if (webSearchRequests > 0)
|
|
5975
|
+
assignNumber("webSearchRequests", webSearchRequests);
|
|
5976
|
+
if (webFetchRequests > 0)
|
|
5977
|
+
assignNumber("webFetchRequests", webFetchRequests);
|
|
5978
|
+
if (serviceTier)
|
|
5979
|
+
assignString("serviceTier", serviceTier);
|
|
5980
|
+
if (speed)
|
|
5981
|
+
assignString("speed", speed);
|
|
5982
|
+
return changed;
|
|
5983
|
+
}
|
|
5984
|
+
ensureObserveMetaRecord(key) {
|
|
5985
|
+
const providerMeta = isRecord(this.session.providerMeta) ? this.session.providerMeta : {};
|
|
5986
|
+
this.session.providerMeta = providerMeta;
|
|
5987
|
+
const existing = providerMeta[key];
|
|
5988
|
+
if (isRecord(existing)) {
|
|
5989
|
+
return existing;
|
|
5990
|
+
}
|
|
5991
|
+
const next = {};
|
|
5992
|
+
providerMeta[key] = next;
|
|
5993
|
+
return next;
|
|
5994
|
+
}
|
|
5995
|
+
assignObserveString(target, key, value) {
|
|
5996
|
+
const next = maybeString(value);
|
|
5997
|
+
if (next) {
|
|
5998
|
+
target[key] = next;
|
|
5999
|
+
}
|
|
6000
|
+
}
|
|
5742
6001
|
handleSystem(record, capturedAt) {
|
|
5743
6002
|
if (record.subtype !== "init") {
|
|
5744
6003
|
return;
|
|
@@ -5768,19 +6027,41 @@ class ClaudeCodeHistoryParser {
|
|
|
5768
6027
|
});
|
|
5769
6028
|
}
|
|
5770
6029
|
}
|
|
6030
|
+
handleUser(record, capturedAt) {
|
|
6031
|
+
const message = record.message && typeof record.message === "object" ? record.message : null;
|
|
6032
|
+
const content = message?.content;
|
|
6033
|
+
if (Array.isArray(content) && content.length > 0) {
|
|
6034
|
+
const toolResults = content.filter((entry) => {
|
|
6035
|
+
return !!entry && typeof entry === "object" && !Array.isArray(entry) && entry.type === "tool_result";
|
|
6036
|
+
});
|
|
6037
|
+
if (toolResults.length === content.length) {
|
|
6038
|
+
for (const toolResult of toolResults) {
|
|
6039
|
+
this.handleToolResult({
|
|
6040
|
+
...toolResult,
|
|
6041
|
+
tool_use_id: typeof toolResult.tool_use_id === "string" ? toolResult.tool_use_id : toolResult.id,
|
|
6042
|
+
is_error: toolResult.is_error === true
|
|
6043
|
+
}, capturedAt);
|
|
6044
|
+
}
|
|
6045
|
+
return;
|
|
6046
|
+
}
|
|
6047
|
+
}
|
|
6048
|
+
this.startTurn(capturedAt);
|
|
6049
|
+
}
|
|
5771
6050
|
handleAssistant(record, capturedAt) {
|
|
5772
6051
|
const turn = this.ensureTurn(capturedAt);
|
|
5773
|
-
if (this.sawStreamTextThisTurn) {
|
|
5774
|
-
return;
|
|
5775
|
-
}
|
|
5776
6052
|
const content = record.message && typeof record.message === "object" ? record.message.content : record.content;
|
|
5777
6053
|
if (!Array.isArray(content)) {
|
|
6054
|
+
this.maybeEndTurnFromAssistant(record, capturedAt);
|
|
5778
6055
|
return;
|
|
5779
6056
|
}
|
|
6057
|
+
const skipTextBlocks = this.sawStreamTextThisTurn;
|
|
5780
6058
|
for (const part of content) {
|
|
5781
6059
|
const contentPart = part;
|
|
5782
6060
|
const contentType = typeof contentPart.type === "string" ? contentPart.type : "";
|
|
5783
6061
|
if (contentType === "thinking" || contentType === "reasoning") {
|
|
6062
|
+
if (skipTextBlocks) {
|
|
6063
|
+
continue;
|
|
6064
|
+
}
|
|
5784
6065
|
const block = this.startBlock(turn, capturedAt, {
|
|
5785
6066
|
type: "reasoning",
|
|
5786
6067
|
text: typeof contentPart.thinking === "string" ? contentPart.thinking : typeof contentPart.text === "string" ? contentPart.text : "",
|
|
@@ -5788,14 +6069,20 @@ class ClaudeCodeHistoryParser {
|
|
|
5788
6069
|
});
|
|
5789
6070
|
this.emitBlockEnd(capturedAt, turn, block, "completed");
|
|
5790
6071
|
} else if (contentType === "text") {
|
|
6072
|
+
if (skipTextBlocks) {
|
|
6073
|
+
continue;
|
|
6074
|
+
}
|
|
5791
6075
|
const block = this.startBlock(turn, capturedAt, {
|
|
5792
6076
|
type: "text",
|
|
5793
6077
|
text: typeof contentPart.text === "string" ? contentPart.text : "",
|
|
5794
6078
|
status: "completed"
|
|
5795
6079
|
});
|
|
5796
6080
|
this.emitBlockEnd(capturedAt, turn, block, "completed");
|
|
6081
|
+
} else if (contentType === "tool_use") {
|
|
6082
|
+
this.handleToolUse(contentPart, capturedAt);
|
|
5797
6083
|
}
|
|
5798
6084
|
}
|
|
6085
|
+
this.maybeEndTurnFromAssistant(record, capturedAt);
|
|
5799
6086
|
}
|
|
5800
6087
|
handleStreamEvent(record, capturedAt) {
|
|
5801
6088
|
const turn = this.ensureTurn(capturedAt);
|
|
@@ -6017,6 +6304,12 @@ class ClaudeCodeHistoryParser {
|
|
|
6017
6304
|
this.emitError(turn, capturedAt, message);
|
|
6018
6305
|
this.endTurn("failed", capturedAt);
|
|
6019
6306
|
}
|
|
6307
|
+
maybeEndTurnFromAssistant(record, capturedAt) {
|
|
6308
|
+
const stopReason = record.message && typeof record.message === "object" ? record.message.stop_reason : record.stop_reason;
|
|
6309
|
+
if (stopReason === "end_turn") {
|
|
6310
|
+
this.endTurn("completed", capturedAt);
|
|
6311
|
+
}
|
|
6312
|
+
}
|
|
6020
6313
|
startTurn(capturedAt) {
|
|
6021
6314
|
if (this.currentTurn) {
|
|
6022
6315
|
this.endTurn("stopped", capturedAt);
|
|
@@ -6839,7 +7132,7 @@ var init_codex_launch_config = () => {};
|
|
|
6839
7132
|
|
|
6840
7133
|
// ../agent-sessions/src/adapters/codex.ts
|
|
6841
7134
|
import { spawn as spawn2 } from "child_process";
|
|
6842
|
-
import { access as access2, appendFile as appendFile2, constants as constants2, mkdir as mkdir4, readFile as
|
|
7135
|
+
import { access as access2, appendFile as appendFile2, constants as constants2, mkdir as mkdir4, readFile as readFile6, rm as rm3, writeFile as writeFile4 } from "fs/promises";
|
|
6843
7136
|
import { delimiter as delimiter2, join as join8 } from "path";
|
|
6844
7137
|
import { homedir as homedir6 } from "os";
|
|
6845
7138
|
function parseJsonLine(line) {
|
|
@@ -6880,7 +7173,7 @@ function errorMessage2(error) {
|
|
|
6880
7173
|
}
|
|
6881
7174
|
async function readOptionalFile(filePath) {
|
|
6882
7175
|
try {
|
|
6883
|
-
const raw = await
|
|
7176
|
+
const raw = await readFile6(filePath, "utf8");
|
|
6884
7177
|
const trimmed = raw.trim();
|
|
6885
7178
|
return trimmed || null;
|
|
6886
7179
|
} catch {
|
|
@@ -9340,12 +9633,13 @@ var init_src = __esm(() => {
|
|
|
9340
9633
|
init_pi();
|
|
9341
9634
|
init_echo();
|
|
9342
9635
|
init_codex_launch_config();
|
|
9636
|
+
init_cost();
|
|
9343
9637
|
});
|
|
9344
9638
|
|
|
9345
9639
|
// ../runtime/src/codex-app-server.ts
|
|
9346
9640
|
import { spawn as spawn3 } from "child_process";
|
|
9347
9641
|
import { constants as constants3 } from "fs";
|
|
9348
|
-
import { access as access3, appendFile as appendFile3, mkdir as mkdir5, readFile as
|
|
9642
|
+
import { access as access3, appendFile as appendFile3, mkdir as mkdir5, readFile as readFile7, rm as rm4, writeFile as writeFile5 } from "fs/promises";
|
|
9349
9643
|
import { delimiter as delimiter3, join as join9 } from "path";
|
|
9350
9644
|
function normalizeCodexModelValue(value) {
|
|
9351
9645
|
const trimmed = value?.trim();
|
|
@@ -9542,7 +9836,7 @@ function isNotification2(message) {
|
|
|
9542
9836
|
}
|
|
9543
9837
|
async function readOptionalFile2(filePath) {
|
|
9544
9838
|
try {
|
|
9545
|
-
const raw = await
|
|
9839
|
+
const raw = await readFile7(filePath, "utf8");
|
|
9546
9840
|
const trimmed = raw.trim();
|
|
9547
9841
|
return trimmed || null;
|
|
9548
9842
|
} catch {
|
|
@@ -10283,12 +10577,227 @@ function buildCollaborationContractPrompt(agentId) {
|
|
|
10283
10577
|
`);
|
|
10284
10578
|
}
|
|
10285
10579
|
|
|
10286
|
-
// ../runtime/src/
|
|
10287
|
-
import {
|
|
10288
|
-
import { existsSync as existsSync7, mkdirSync as mkdirSync2, readFileSync as readFileSync3, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
10580
|
+
// ../runtime/src/tool-resolution.ts
|
|
10581
|
+
import { accessSync as accessSync2, constants as constants4, existsSync as existsSync7 } from "fs";
|
|
10289
10582
|
import { homedir as homedir7 } from "os";
|
|
10290
10583
|
import { basename as basename3, dirname as dirname5, join as join10, resolve as resolve6 } from "path";
|
|
10291
10584
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
10585
|
+
function expandHomePath3(value, env = process.env) {
|
|
10586
|
+
const home = env.HOME ?? homedir7();
|
|
10587
|
+
if (value === "~") {
|
|
10588
|
+
return home;
|
|
10589
|
+
}
|
|
10590
|
+
if (value.startsWith("~/")) {
|
|
10591
|
+
return join10(home, value.slice(2));
|
|
10592
|
+
}
|
|
10593
|
+
return value;
|
|
10594
|
+
}
|
|
10595
|
+
function isExecutablePath(candidate) {
|
|
10596
|
+
if (!candidate) {
|
|
10597
|
+
return false;
|
|
10598
|
+
}
|
|
10599
|
+
try {
|
|
10600
|
+
accessSync2(candidate, constants4.X_OK);
|
|
10601
|
+
return true;
|
|
10602
|
+
} catch {
|
|
10603
|
+
return false;
|
|
10604
|
+
}
|
|
10605
|
+
}
|
|
10606
|
+
function splitPathEntries(env = process.env) {
|
|
10607
|
+
const separator = process.platform === "win32" ? ";" : ":";
|
|
10608
|
+
return (env.PATH ?? "").split(separator).filter(Boolean);
|
|
10609
|
+
}
|
|
10610
|
+
function dedupeDirectories(values, env) {
|
|
10611
|
+
const seen = new Set;
|
|
10612
|
+
const resolvedEntries = [];
|
|
10613
|
+
for (const value of values) {
|
|
10614
|
+
const normalized = resolve6(expandHomePath3(value, env));
|
|
10615
|
+
if (seen.has(normalized)) {
|
|
10616
|
+
continue;
|
|
10617
|
+
}
|
|
10618
|
+
seen.add(normalized);
|
|
10619
|
+
resolvedEntries.push(normalized);
|
|
10620
|
+
}
|
|
10621
|
+
return resolvedEntries;
|
|
10622
|
+
}
|
|
10623
|
+
function resolveExecutableFromSearch(options) {
|
|
10624
|
+
const env = options.env ?? process.env;
|
|
10625
|
+
const envKeys = options.envKeys ?? [];
|
|
10626
|
+
for (const envKey of envKeys) {
|
|
10627
|
+
const explicit = env[envKey]?.trim();
|
|
10628
|
+
if (!explicit) {
|
|
10629
|
+
continue;
|
|
10630
|
+
}
|
|
10631
|
+
const expanded = expandHomePath3(explicit, env);
|
|
10632
|
+
if (isExecutablePath(expanded)) {
|
|
10633
|
+
return { path: resolve6(expanded), source: "env" };
|
|
10634
|
+
}
|
|
10635
|
+
const foundOnPath = findExecutableOnSearchPath(explicit, env);
|
|
10636
|
+
if (foundOnPath) {
|
|
10637
|
+
return { path: foundOnPath.path, source: "env" };
|
|
10638
|
+
}
|
|
10639
|
+
}
|
|
10640
|
+
const commonDirectories = dedupeDirectories([...options.commonDirectories ?? DEFAULT_COMMON_EXECUTABLE_DIRECTORIES], env);
|
|
10641
|
+
const searchDirectories = dedupeDirectories([
|
|
10642
|
+
...splitPathEntries(env),
|
|
10643
|
+
...options.extraDirectories ?? [],
|
|
10644
|
+
...commonDirectories
|
|
10645
|
+
], env);
|
|
10646
|
+
for (const directory of searchDirectories) {
|
|
10647
|
+
for (const name of options.names) {
|
|
10648
|
+
const candidate = join10(directory, name);
|
|
10649
|
+
if (isExecutablePath(candidate)) {
|
|
10650
|
+
return {
|
|
10651
|
+
path: candidate,
|
|
10652
|
+
source: commonDirectories.includes(directory) ? "common-path" : "path"
|
|
10653
|
+
};
|
|
10654
|
+
}
|
|
10655
|
+
}
|
|
10656
|
+
}
|
|
10657
|
+
return null;
|
|
10658
|
+
}
|
|
10659
|
+
function resolveBunExecutable2(env = process.env) {
|
|
10660
|
+
return resolveExecutableFromSearch({
|
|
10661
|
+
env,
|
|
10662
|
+
envKeys: ["OPENSCOUT_BUN_BIN", "SCOUT_BUN_BIN", "BUN_BIN"],
|
|
10663
|
+
names: ["bun"]
|
|
10664
|
+
});
|
|
10665
|
+
}
|
|
10666
|
+
function resolveJavaScriptRuntime(options = {}) {
|
|
10667
|
+
const env = options.env ?? process.env;
|
|
10668
|
+
const allowNode = options.allowNode ?? true;
|
|
10669
|
+
const allowBun = options.allowBun ?? true;
|
|
10670
|
+
const explicitEnvKeys = options.explicitEnvKeys ?? [];
|
|
10671
|
+
for (const envKey of explicitEnvKeys) {
|
|
10672
|
+
const explicit = env[envKey]?.trim();
|
|
10673
|
+
if (!explicit) {
|
|
10674
|
+
continue;
|
|
10675
|
+
}
|
|
10676
|
+
const expanded = expandHomePath3(explicit, env);
|
|
10677
|
+
const resolvedExplicit = isExecutablePath(expanded) ? resolve6(expanded) : findExecutableOnSearchPath(explicit, env)?.path;
|
|
10678
|
+
if (!resolvedExplicit) {
|
|
10679
|
+
continue;
|
|
10680
|
+
}
|
|
10681
|
+
const kind = javascriptRuntimeKindForPath(resolvedExplicit);
|
|
10682
|
+
if (kind === "node" && allowNode || kind === "bun" && allowBun) {
|
|
10683
|
+
return {
|
|
10684
|
+
path: resolvedExplicit,
|
|
10685
|
+
kind,
|
|
10686
|
+
source: "env"
|
|
10687
|
+
};
|
|
10688
|
+
}
|
|
10689
|
+
}
|
|
10690
|
+
if (options.preferCurrentExecutable ?? true) {
|
|
10691
|
+
const currentExecutable = process.execPath;
|
|
10692
|
+
const kind = javascriptRuntimeKindForPath(currentExecutable);
|
|
10693
|
+
if (kind === "node" && allowNode || kind === "bun" && allowBun) {
|
|
10694
|
+
return {
|
|
10695
|
+
path: currentExecutable,
|
|
10696
|
+
kind,
|
|
10697
|
+
source: "execPath"
|
|
10698
|
+
};
|
|
10699
|
+
}
|
|
10700
|
+
}
|
|
10701
|
+
const searchNames = [];
|
|
10702
|
+
if (allowNode) {
|
|
10703
|
+
searchNames.push("node");
|
|
10704
|
+
}
|
|
10705
|
+
if (allowBun) {
|
|
10706
|
+
searchNames.push("bun");
|
|
10707
|
+
}
|
|
10708
|
+
const resolvedExecutable = resolveExecutableFromSearch({
|
|
10709
|
+
env,
|
|
10710
|
+
names: searchNames
|
|
10711
|
+
});
|
|
10712
|
+
if (!resolvedExecutable) {
|
|
10713
|
+
return null;
|
|
10714
|
+
}
|
|
10715
|
+
return {
|
|
10716
|
+
path: resolvedExecutable.path,
|
|
10717
|
+
kind: javascriptRuntimeKindForPath(resolvedExecutable.path),
|
|
10718
|
+
source: resolvedExecutable.source
|
|
10719
|
+
};
|
|
10720
|
+
}
|
|
10721
|
+
function resolveBundledEntrypoint(moduleUrl, filename) {
|
|
10722
|
+
const moduleDirectory = dirname5(fileURLToPath4(moduleUrl));
|
|
10723
|
+
const candidate = join10(moduleDirectory, filename);
|
|
10724
|
+
return existsSync7(candidate) ? candidate : null;
|
|
10725
|
+
}
|
|
10726
|
+
function resolveOpenScoutRepoRoot(options = {}) {
|
|
10727
|
+
const starts = options.startDirectories?.map((entry) => entry?.trim()).filter((entry) => Boolean(entry));
|
|
10728
|
+
if (!starts || starts.length === 0) {
|
|
10729
|
+
return null;
|
|
10730
|
+
}
|
|
10731
|
+
for (const start of starts) {
|
|
10732
|
+
let current = resolve6(start);
|
|
10733
|
+
while (true) {
|
|
10734
|
+
const scoutEntry = join10(current, "apps", "desktop", "bin", "scout.ts");
|
|
10735
|
+
const runtimeEntry = join10(current, "packages", "runtime", "bin", "openscout-runtime.mjs");
|
|
10736
|
+
if (existsSync7(scoutEntry) && existsSync7(runtimeEntry)) {
|
|
10737
|
+
return current;
|
|
10738
|
+
}
|
|
10739
|
+
const parent = dirname5(current);
|
|
10740
|
+
if (parent === current) {
|
|
10741
|
+
break;
|
|
10742
|
+
}
|
|
10743
|
+
current = parent;
|
|
10744
|
+
}
|
|
10745
|
+
}
|
|
10746
|
+
return null;
|
|
10747
|
+
}
|
|
10748
|
+
function resolveRepoEntrypoint(repoRoot, relativePath) {
|
|
10749
|
+
if (!repoRoot) {
|
|
10750
|
+
return null;
|
|
10751
|
+
}
|
|
10752
|
+
const candidate = join10(repoRoot, relativePath);
|
|
10753
|
+
return existsSync7(candidate) ? candidate : null;
|
|
10754
|
+
}
|
|
10755
|
+
function resolveNodeModulesPackageEntrypoint(moduleUrl, packageSegments, entryRelativePath) {
|
|
10756
|
+
let current = dirname5(fileURLToPath4(moduleUrl));
|
|
10757
|
+
for (let attempt = 0;attempt < 24; attempt += 1) {
|
|
10758
|
+
const candidate = join10(current, "node_modules", ...packageSegments, entryRelativePath);
|
|
10759
|
+
if (existsSync7(candidate)) {
|
|
10760
|
+
return candidate;
|
|
10761
|
+
}
|
|
10762
|
+
const parent = dirname5(current);
|
|
10763
|
+
if (parent === current) {
|
|
10764
|
+
break;
|
|
10765
|
+
}
|
|
10766
|
+
current = parent;
|
|
10767
|
+
}
|
|
10768
|
+
return null;
|
|
10769
|
+
}
|
|
10770
|
+
function javascriptRuntimeKindForPath(filePath) {
|
|
10771
|
+
return basename3(filePath).toLowerCase().startsWith("bun") ? "bun" : "node";
|
|
10772
|
+
}
|
|
10773
|
+
function findExecutableOnSearchPath(name, env) {
|
|
10774
|
+
const searchDirectories = dedupeDirectories([
|
|
10775
|
+
...splitPathEntries(env),
|
|
10776
|
+
...DEFAULT_COMMON_EXECUTABLE_DIRECTORIES
|
|
10777
|
+
], env);
|
|
10778
|
+
for (const directory of searchDirectories) {
|
|
10779
|
+
const candidate = join10(directory, name);
|
|
10780
|
+
if (isExecutablePath(candidate)) {
|
|
10781
|
+
return { path: candidate, source: "path" };
|
|
10782
|
+
}
|
|
10783
|
+
}
|
|
10784
|
+
return null;
|
|
10785
|
+
}
|
|
10786
|
+
var DEFAULT_COMMON_EXECUTABLE_DIRECTORIES;
|
|
10787
|
+
var init_tool_resolution = __esm(() => {
|
|
10788
|
+
DEFAULT_COMMON_EXECUTABLE_DIRECTORIES = [
|
|
10789
|
+
join10(homedir7(), ".bun", "bin"),
|
|
10790
|
+
"/opt/homebrew/bin",
|
|
10791
|
+
"/usr/local/bin"
|
|
10792
|
+
];
|
|
10793
|
+
});
|
|
10794
|
+
|
|
10795
|
+
// ../runtime/src/broker-service.ts
|
|
10796
|
+
import { spawnSync } from "child_process";
|
|
10797
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync2, readFileSync as readFileSync3, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
10798
|
+
import { homedir as homedir8 } from "os";
|
|
10799
|
+
import { dirname as dirname6, join as join11, resolve as resolve7 } from "path";
|
|
10800
|
+
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
10292
10801
|
function isTmpPath(p) {
|
|
10293
10802
|
return /^\/(?:private\/)?tmp\//.test(p);
|
|
10294
10803
|
}
|
|
@@ -10320,17 +10829,17 @@ function runtimePackageDir() {
|
|
|
10320
10829
|
const fromCwd = findWorkspaceRuntimeDir(process.cwd());
|
|
10321
10830
|
if (fromCwd)
|
|
10322
10831
|
return fromCwd;
|
|
10323
|
-
const moduleDir =
|
|
10324
|
-
return
|
|
10832
|
+
const moduleDir = dirname6(fileURLToPath5(import.meta.url));
|
|
10833
|
+
return resolve7(moduleDir, "..");
|
|
10325
10834
|
}
|
|
10326
10835
|
function isInstalledRuntimePackageDir(candidate) {
|
|
10327
|
-
return
|
|
10836
|
+
return existsSync8(join11(candidate, "package.json")) && existsSync8(join11(candidate, "bin", "openscout-runtime.mjs"));
|
|
10328
10837
|
}
|
|
10329
10838
|
function findGlobalRuntimeDir() {
|
|
10330
10839
|
const candidates = [
|
|
10331
|
-
|
|
10332
|
-
|
|
10333
|
-
|
|
10840
|
+
join11(homedir8(), ".bun", "node_modules", "@openscout", "runtime"),
|
|
10841
|
+
join11(homedir8(), ".bun", "install", "global", "node_modules", "@openscout", "runtime"),
|
|
10842
|
+
join11(homedir8(), ".bun", "install", "global", "node_modules", "@openscout", "scout", "node_modules", "@openscout", "runtime")
|
|
10334
10843
|
];
|
|
10335
10844
|
for (const c of candidates) {
|
|
10336
10845
|
if (isInstalledRuntimePackageDir(c))
|
|
@@ -10340,11 +10849,11 @@ function findGlobalRuntimeDir() {
|
|
|
10340
10849
|
const result = spawnSync("which", ["scout"], { encoding: "utf8", timeout: 3000 });
|
|
10341
10850
|
const scoutBin = result.stdout?.trim();
|
|
10342
10851
|
if (scoutBin) {
|
|
10343
|
-
const scoutPkg =
|
|
10344
|
-
const nested =
|
|
10852
|
+
const scoutPkg = resolve7(scoutBin, "..", "..");
|
|
10853
|
+
const nested = join11(scoutPkg, "node_modules", "@openscout", "runtime");
|
|
10345
10854
|
if (isInstalledRuntimePackageDir(nested))
|
|
10346
10855
|
return nested;
|
|
10347
|
-
const sibling =
|
|
10856
|
+
const sibling = resolve7(scoutPkg, "..", "runtime");
|
|
10348
10857
|
if (isInstalledRuntimePackageDir(sibling))
|
|
10349
10858
|
return sibling;
|
|
10350
10859
|
}
|
|
@@ -10352,38 +10861,24 @@ function findGlobalRuntimeDir() {
|
|
|
10352
10861
|
return null;
|
|
10353
10862
|
}
|
|
10354
10863
|
function findWorkspaceRuntimeDir(startDir) {
|
|
10355
|
-
let current =
|
|
10864
|
+
let current = resolve7(startDir);
|
|
10356
10865
|
while (true) {
|
|
10357
|
-
const candidate =
|
|
10358
|
-
if (
|
|
10866
|
+
const candidate = join11(current, "packages", "runtime");
|
|
10867
|
+
if (existsSync8(join11(candidate, "package.json")) && existsSync8(join11(candidate, "src"))) {
|
|
10359
10868
|
return candidate;
|
|
10360
10869
|
}
|
|
10361
|
-
const parent =
|
|
10870
|
+
const parent = dirname6(current);
|
|
10362
10871
|
if (parent === current)
|
|
10363
10872
|
return null;
|
|
10364
10873
|
current = parent;
|
|
10365
10874
|
}
|
|
10366
10875
|
}
|
|
10367
|
-
function
|
|
10368
|
-
const
|
|
10369
|
-
if (
|
|
10370
|
-
return
|
|
10876
|
+
function resolveBunExecutable3() {
|
|
10877
|
+
const bun = resolveBunExecutable2(process.env);
|
|
10878
|
+
if (bun) {
|
|
10879
|
+
return bun.path;
|
|
10371
10880
|
}
|
|
10372
|
-
|
|
10373
|
-
return process.execPath;
|
|
10374
|
-
}
|
|
10375
|
-
const pathEntries = (process.env.PATH ?? "").split(":").filter(Boolean);
|
|
10376
|
-
for (const entry of pathEntries) {
|
|
10377
|
-
const candidate = join10(entry, "bun");
|
|
10378
|
-
if (existsSync7(candidate)) {
|
|
10379
|
-
return candidate;
|
|
10380
|
-
}
|
|
10381
|
-
}
|
|
10382
|
-
const homeBun = join10(homedir7(), ".bun", "bin", "bun");
|
|
10383
|
-
if (existsSync7(homeBun)) {
|
|
10384
|
-
return homeBun;
|
|
10385
|
-
}
|
|
10386
|
-
return "bun";
|
|
10881
|
+
throw new Error("Unable to locate Bun for broker service management. Install Bun or set OPENSCOUT_BUN_BIN.");
|
|
10387
10882
|
}
|
|
10388
10883
|
function resolveBrokerServiceMode() {
|
|
10389
10884
|
const explicit = (process.env.OPENSCOUT_BROKER_SERVICE_MODE ?? "").trim().toLowerCase();
|
|
@@ -10422,15 +10917,15 @@ function resolveBrokerServiceConfig() {
|
|
|
10422
10917
|
const label = resolveBrokerServiceLabel(mode);
|
|
10423
10918
|
const uid = typeof process.getuid === "function" ? process.getuid() : Number.parseInt(process.env.UID ?? "0", 10);
|
|
10424
10919
|
const supportPaths = resolveOpenScoutSupportPaths();
|
|
10425
|
-
const defaultSupportDir =
|
|
10920
|
+
const defaultSupportDir = join11(homedir8(), "Library", "Application Support", "OpenScout");
|
|
10426
10921
|
const supportDirectory = isTmpPath(supportPaths.supportDirectory) ? defaultSupportDir : supportPaths.supportDirectory;
|
|
10427
|
-
const logsDirectory =
|
|
10428
|
-
const controlHome = isTmpPath(supportPaths.controlHome) ?
|
|
10922
|
+
const logsDirectory = join11(supportDirectory, "logs", "broker");
|
|
10923
|
+
const controlHome = isTmpPath(supportPaths.controlHome) ? join11(homedir8(), ".openscout", "control-plane") : supportPaths.controlHome;
|
|
10429
10924
|
const advertiseScope = resolveAdvertiseScope();
|
|
10430
10925
|
const brokerHost = resolveBrokerHost(advertiseScope);
|
|
10431
10926
|
const brokerPort = Number.parseInt(process.env.OPENSCOUT_BROKER_PORT ?? String(DEFAULT_BROKER_PORT), 10);
|
|
10432
10927
|
const brokerUrl = process.env.OPENSCOUT_BROKER_URL ?? buildDefaultBrokerUrl(brokerHost, brokerPort);
|
|
10433
|
-
const launchAgentPath =
|
|
10928
|
+
const launchAgentPath = join11(homedir8(), "Library", "LaunchAgents", `${label}.plist`);
|
|
10434
10929
|
return {
|
|
10435
10930
|
label,
|
|
10436
10931
|
mode,
|
|
@@ -10440,11 +10935,11 @@ function resolveBrokerServiceConfig() {
|
|
|
10440
10935
|
launchAgentPath,
|
|
10441
10936
|
supportDirectory,
|
|
10442
10937
|
logsDirectory,
|
|
10443
|
-
stdoutLogPath:
|
|
10444
|
-
stderrLogPath:
|
|
10938
|
+
stdoutLogPath: join11(logsDirectory, "stdout.log"),
|
|
10939
|
+
stderrLogPath: join11(logsDirectory, "stderr.log"),
|
|
10445
10940
|
controlHome,
|
|
10446
10941
|
runtimePackageDir: runtimePackageDir(),
|
|
10447
|
-
bunExecutable:
|
|
10942
|
+
bunExecutable: resolveBunExecutable3(),
|
|
10448
10943
|
brokerHost,
|
|
10449
10944
|
brokerPort,
|
|
10450
10945
|
brokerUrl,
|
|
@@ -10461,7 +10956,7 @@ function renderLaunchAgentPlist(config) {
|
|
|
10461
10956
|
OPENSCOUT_BROKER_SERVICE_MODE: config.mode,
|
|
10462
10957
|
OPENSCOUT_BROKER_SERVICE_LABEL: config.label,
|
|
10463
10958
|
OPENSCOUT_ADVERTISE_SCOPE: config.advertiseScope,
|
|
10464
|
-
HOME:
|
|
10959
|
+
HOME: homedir8(),
|
|
10465
10960
|
PATH: launchPath,
|
|
10466
10961
|
...collectOptionalEnvVars([
|
|
10467
10962
|
"OPENSCOUT_MESH_ID",
|
|
@@ -10487,7 +10982,7 @@ function renderLaunchAgentPlist(config) {
|
|
|
10487
10982
|
<key>ProgramArguments</key>
|
|
10488
10983
|
<array>
|
|
10489
10984
|
<string>${xmlEscape(config.bunExecutable)}</string>
|
|
10490
|
-
<string>${xmlEscape(
|
|
10985
|
+
<string>${xmlEscape(join11(config.runtimePackageDir, "bin", "openscout-runtime.mjs"))}</string>
|
|
10491
10986
|
<string>broker</string>
|
|
10492
10987
|
</array>
|
|
10493
10988
|
<key>WorkingDirectory</key>
|
|
@@ -10522,7 +11017,7 @@ function collectOptionalEnvVars(keys) {
|
|
|
10522
11017
|
}
|
|
10523
11018
|
function resolveLaunchAgentPATH() {
|
|
10524
11019
|
const entries = [
|
|
10525
|
-
|
|
11020
|
+
join11(homedir8(), ".bun", "bin"),
|
|
10526
11021
|
...(process.env.PATH ?? "").split(":").filter(Boolean),
|
|
10527
11022
|
"/opt/homebrew/bin",
|
|
10528
11023
|
"/usr/local/bin",
|
|
@@ -10537,7 +11032,7 @@ function xmlEscape(value) {
|
|
|
10537
11032
|
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
10538
11033
|
}
|
|
10539
11034
|
function ensureParentDirectory(filePath) {
|
|
10540
|
-
mkdirSync2(
|
|
11035
|
+
mkdirSync2(dirname6(filePath), { recursive: true });
|
|
10541
11036
|
}
|
|
10542
11037
|
function ensureServiceDirectories(config) {
|
|
10543
11038
|
ensureOpenScoutCleanSlateSync();
|
|
@@ -10570,7 +11065,7 @@ function launchctlPath() {
|
|
|
10570
11065
|
return "/bin/launchctl";
|
|
10571
11066
|
}
|
|
10572
11067
|
function readLogLines(path) {
|
|
10573
|
-
if (!
|
|
11068
|
+
if (!existsSync8(path)) {
|
|
10574
11069
|
return [];
|
|
10575
11070
|
}
|
|
10576
11071
|
return readFileSync3(path, "utf8").split(`
|
|
@@ -10670,7 +11165,7 @@ async function brokerServiceStatus(config = resolveBrokerServiceConfig()) {
|
|
|
10670
11165
|
ensureServiceDirectories(config);
|
|
10671
11166
|
const launchctl = inspectLaunchctl(config);
|
|
10672
11167
|
const health = await fetchHealthSnapshot(config);
|
|
10673
|
-
const installed =
|
|
11168
|
+
const installed = existsSync8(config.launchAgentPath);
|
|
10674
11169
|
const lastLogLine = health.reachable ? readLastLogLine([config.stdoutLogPath, config.stderrLogPath]) : readLastLogLine([config.stderrLogPath, config.stdoutLogPath]);
|
|
10675
11170
|
return {
|
|
10676
11171
|
label: config.label,
|
|
@@ -10713,7 +11208,7 @@ async function startBrokerService(config = resolveBrokerServiceConfig()) {
|
|
|
10713
11208
|
throw new Error(status.lastLogLine ?? status.health.error ?? "Broker service did not become healthy.");
|
|
10714
11209
|
}
|
|
10715
11210
|
function sleep(ms) {
|
|
10716
|
-
return new Promise((
|
|
11211
|
+
return new Promise((resolve8) => setTimeout(resolve8, ms));
|
|
10717
11212
|
}
|
|
10718
11213
|
async function stopBrokerService(config = resolveBrokerServiceConfig()) {
|
|
10719
11214
|
runCommand(launchctlPath(), ["bootout", config.serviceTarget], { allowFailure: true });
|
|
@@ -10732,7 +11227,7 @@ async function restartBrokerService(config = resolveBrokerServiceConfig()) {
|
|
|
10732
11227
|
}
|
|
10733
11228
|
async function uninstallBrokerService(config = resolveBrokerServiceConfig()) {
|
|
10734
11229
|
await stopBrokerService(config);
|
|
10735
|
-
if (
|
|
11230
|
+
if (existsSync8(config.launchAgentPath)) {
|
|
10736
11231
|
rmSync2(config.launchAgentPath, { force: true });
|
|
10737
11232
|
}
|
|
10738
11233
|
return brokerServiceStatus(config);
|
|
@@ -10793,8 +11288,9 @@ function formatBrokerServiceStatus(status) {
|
|
|
10793
11288
|
var DEFAULT_BROKER_HOST = "127.0.0.1", DEFAULT_BROKER_HOST_MESH = "0.0.0.0", DEFAULT_BROKER_PORT = 65535, DEFAULT_ADVERTISE_SCOPE = "local", BROKER_SERVICE_POLL_INTERVAL_MS = 100, DEFAULT_BROKER_START_TIMEOUT_MS = 15000, DEFAULT_BROKER_URL;
|
|
10794
11289
|
var init_broker_service = __esm(async () => {
|
|
10795
11290
|
init_support_paths();
|
|
11291
|
+
init_tool_resolution();
|
|
10796
11292
|
DEFAULT_BROKER_URL = buildDefaultBrokerUrl();
|
|
10797
|
-
if (process.argv[1] &&
|
|
11293
|
+
if (process.argv[1] && fileURLToPath5(import.meta.url) === process.argv[1] && !process.argv[1].endsWith("/main.mjs")) {
|
|
10798
11294
|
await main();
|
|
10799
11295
|
}
|
|
10800
11296
|
});
|
|
@@ -10811,27 +11307,27 @@ var init_local_agent_template = __esm(() => {
|
|
|
10811
11307
|
|
|
10812
11308
|
// ../runtime/src/local-agents.ts
|
|
10813
11309
|
import { execFileSync as execFileSync3, execSync } from "child_process";
|
|
10814
|
-
import { existsSync as
|
|
11310
|
+
import { existsSync as existsSync9, readFileSync as readFileSync4 } from "fs";
|
|
10815
11311
|
import { mkdir as mkdir6, rm as rm5, stat as stat3, writeFile as writeFile6 } from "fs/promises";
|
|
10816
|
-
import { basename as
|
|
10817
|
-
import { fileURLToPath as
|
|
11312
|
+
import { basename as basename5, dirname as dirname7, join as join12, resolve as resolve8 } from "path";
|
|
11313
|
+
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
10818
11314
|
function resolveRelayHub() {
|
|
10819
11315
|
return resolveOpenScoutSupportPaths().relayHubDirectory;
|
|
10820
11316
|
}
|
|
10821
11317
|
function resolveProjectsRoot(projectPath) {
|
|
10822
11318
|
if (process.env.OPENSCOUT_PROJECTS_ROOT?.trim()) {
|
|
10823
|
-
return
|
|
11319
|
+
return resolve8(process.env.OPENSCOUT_PROJECTS_ROOT.trim());
|
|
10824
11320
|
}
|
|
10825
11321
|
try {
|
|
10826
11322
|
const supportPaths = resolveOpenScoutSupportPaths();
|
|
10827
|
-
if (!
|
|
10828
|
-
return
|
|
11323
|
+
if (!existsSync9(supportPaths.settingsPath)) {
|
|
11324
|
+
return dirname7(projectPath);
|
|
10829
11325
|
}
|
|
10830
11326
|
const raw = JSON.parse(readFileSync4(supportPaths.settingsPath, "utf8"));
|
|
10831
11327
|
const workspaceRoot = raw.discovery?.workspaceRoots?.find((entry) => typeof entry === "string" && entry.trim().length > 0);
|
|
10832
|
-
return workspaceRoot ?
|
|
11328
|
+
return workspaceRoot ? resolve8(workspaceRoot) : dirname7(projectPath);
|
|
10833
11329
|
} catch {
|
|
10834
|
-
return
|
|
11330
|
+
return dirname7(projectPath);
|
|
10835
11331
|
}
|
|
10836
11332
|
}
|
|
10837
11333
|
function resolveBrokerUrl() {
|
|
@@ -10841,7 +11337,7 @@ function nowSeconds2() {
|
|
|
10841
11337
|
return Math.floor(Date.now() / 1000);
|
|
10842
11338
|
}
|
|
10843
11339
|
function scoutCliPath() {
|
|
10844
|
-
return
|
|
11340
|
+
return join12(OPENSCOUT_REPO_ROOT, "packages", "cli", "bin", "scout.mjs");
|
|
10845
11341
|
}
|
|
10846
11342
|
function legacyNodeBrokerRelayCommand() {
|
|
10847
11343
|
return `node ${JSON.stringify(scoutCliPath())}`;
|
|
@@ -10854,13 +11350,13 @@ function titleCaseLocalAgentName(value) {
|
|
|
10854
11350
|
}
|
|
10855
11351
|
function resolveScoutSkillPath() {
|
|
10856
11352
|
const candidatePaths = [
|
|
10857
|
-
|
|
10858
|
-
|
|
10859
|
-
|
|
10860
|
-
|
|
11353
|
+
join12(OPENSCOUT_REPO_ROOT, ".agents", "skills", "scout", "SKILL.md"),
|
|
11354
|
+
join12(process.env.HOME ?? "", ".agents", "skills", "scout", "SKILL.md"),
|
|
11355
|
+
join12(OPENSCOUT_REPO_ROOT, ".agents", "skills", "relay-agent-comms", "SKILL.md"),
|
|
11356
|
+
join12(process.env.HOME ?? "", ".agents", "skills", "relay-agent-comms", "SKILL.md")
|
|
10861
11357
|
];
|
|
10862
11358
|
for (const path of candidatePaths) {
|
|
10863
|
-
if (
|
|
11359
|
+
if (existsSync9(path)) {
|
|
10864
11360
|
return path;
|
|
10865
11361
|
}
|
|
10866
11362
|
}
|
|
@@ -10911,7 +11407,7 @@ function buildLocalAgentCollaborationPrompt(context) {
|
|
|
10911
11407
|
function buildLocalAgentTmuxProtocolPrompt(context) {
|
|
10912
11408
|
return [
|
|
10913
11409
|
"Relay protocol:",
|
|
10914
|
-
` - Read recent context with: ${context.relayCommand}
|
|
11410
|
+
` - Read recent context when needed with: ${context.relayCommand} latest --agent ${context.agentId} --limit 20`,
|
|
10915
11411
|
` - Tell one agent with: ${context.relayCommand} send --as ${context.agentId} "@<agent> your message"`,
|
|
10916
11412
|
` - Ask one agent and stay attached with: ${context.relayCommand} ask --to <agent> --as ${context.agentId} "your request"`,
|
|
10917
11413
|
"",
|
|
@@ -10923,9 +11419,10 @@ function buildLocalAgentTmuxProtocolPrompt(context) {
|
|
|
10923
11419
|
" - If you need multiple agents, use separate DMs or an explicit channel; do not guess a venue from multiple mentions",
|
|
10924
11420
|
" - Do not use channel.shared for ordinary delegation or follow-up; reserve it for explicit group updates or broadcasts",
|
|
10925
11421
|
" - If a short @handle may be ambiguous, resolve the exact target before sending; do not guess and do not fall back to shared",
|
|
11422
|
+
" - Treat known offline / on-demand agents as wakeable: use send or ask first and let the broker wake them; only surface ambiguity or unknown-target failures to the operator",
|
|
10926
11423
|
" - Use send for tells and status; use ask when the meaning is 'do this and get back to me'",
|
|
10927
11424
|
" - When replying to an [ask:<id>] request, include the same [ask:<id>] tag in your reply",
|
|
10928
|
-
" - Use the broker-backed
|
|
11425
|
+
" - Use the broker-backed latest command above only when recent context is needed before responding",
|
|
10929
11426
|
` - Follow the scout skill at ${context.scoutSkill} for agent-to-agent communication`
|
|
10930
11427
|
].join(`
|
|
10931
11428
|
`);
|
|
@@ -10936,7 +11433,7 @@ function buildLocalAgentDirectProtocolPrompt(context) {
|
|
|
10936
11433
|
" - You are invoked directly by the OpenScout broker",
|
|
10937
11434
|
" - Return your final answer in the assistant message for the current turn",
|
|
10938
11435
|
" - Do not shell out to send the final answer through relay yourself",
|
|
10939
|
-
` - If you need recent
|
|
11436
|
+
` - If you need recent broker context, inspect it with: ${context.relayCommand} latest --agent ${context.agentId} --limit 20`,
|
|
10940
11437
|
` - If you need to tell one agent something, use: ${context.relayCommand} send --as ${context.agentId} "@<agent> your message"`,
|
|
10941
11438
|
` - If you need another agent to do work, use: ${context.relayCommand} ask --to <agent> --as ${context.agentId} "your request"`,
|
|
10942
11439
|
" - Default Scout loop: resolve identity, resolve one target, choose DM vs explicit channel, keep follow-up in that same venue",
|
|
@@ -10944,6 +11441,7 @@ function buildLocalAgentDirectProtocolPrompt(context) {
|
|
|
10944
11441
|
" - If you need multiple agents, use separate DMs or an explicit channel; do not guess a venue from multiple mentions",
|
|
10945
11442
|
" - Do not use channel.shared for ordinary delegation or follow-up; reserve it for explicit group updates or broadcasts",
|
|
10946
11443
|
" - If a short @handle may be ambiguous, resolve the exact target before sending; do not guess and do not fall back to shared",
|
|
11444
|
+
" - Treat known offline / on-demand agents as wakeable: use send or ask first and let the broker wake them; only surface ambiguity or unknown-target failures to the operator",
|
|
10947
11445
|
" - Use send for tells and status; use ask when the meaning is 'do this and get back to me'",
|
|
10948
11446
|
` - Follow the scout skill at ${context.scoutSkill} for agent-to-agent communication`
|
|
10949
11447
|
].join(`
|
|
@@ -11006,7 +11504,7 @@ function buildLegacySimpleRelayPrompt(agentId, projectName, projectPath, relayCo
|
|
|
11006
11504
|
"A primary agent may call into you for context, execution, follow-through, and handoff.",
|
|
11007
11505
|
"",
|
|
11008
11506
|
`You have full access to the codebase at ${projectPath}.`,
|
|
11009
|
-
`There is a structured relay event stream at ${
|
|
11507
|
+
`There is a structured relay event stream at ${join12(relayHub, "channel.jsonl")} shared by all agents.`,
|
|
11010
11508
|
"",
|
|
11011
11509
|
"Your job:",
|
|
11012
11510
|
` - Respond to @${agentId} mentions from other agents`,
|
|
@@ -11110,17 +11608,17 @@ async function writeLocalAgentRegistry(registry) {
|
|
|
11110
11608
|
}
|
|
11111
11609
|
await writeRelayAgentOverrides(nextOverrides);
|
|
11112
11610
|
}
|
|
11113
|
-
function
|
|
11611
|
+
function expandHomePath4(value) {
|
|
11114
11612
|
if (value === "~") {
|
|
11115
11613
|
return process.env.HOME ?? process.cwd();
|
|
11116
11614
|
}
|
|
11117
11615
|
if (value.startsWith("~/")) {
|
|
11118
|
-
return
|
|
11616
|
+
return join12(process.env.HOME ?? process.cwd(), value.slice(2));
|
|
11119
11617
|
}
|
|
11120
11618
|
return value;
|
|
11121
11619
|
}
|
|
11122
11620
|
function normalizeProjectPath(value) {
|
|
11123
|
-
return
|
|
11621
|
+
return resolve8(expandHomePath4(value.trim() || "."));
|
|
11124
11622
|
}
|
|
11125
11623
|
function normalizeTmuxSessionName2(value, agentId) {
|
|
11126
11624
|
const fallback = `relay-${agentId}`;
|
|
@@ -11383,7 +11881,7 @@ function recordForHarness(record, harnessOverride) {
|
|
|
11383
11881
|
function normalizeLocalAgentRecord(agentId, record) {
|
|
11384
11882
|
const cwd = normalizeProjectPath(record.cwd || process.cwd());
|
|
11385
11883
|
const projectRoot = normalizeProjectPath(record.projectRoot || cwd);
|
|
11386
|
-
const project = record.project?.trim() ||
|
|
11884
|
+
const project = record.project?.trim() || basename5(projectRoot);
|
|
11387
11885
|
const definitionId = record.definitionId?.trim() || agentId;
|
|
11388
11886
|
const defaultHarness = activeLocalHarness(record);
|
|
11389
11887
|
const harnessProfiles = normalizeLocalHarnessProfiles(agentId, {
|
|
@@ -11448,7 +11946,7 @@ function localAgentRecordFromResolvedConfig(config) {
|
|
|
11448
11946
|
function localAgentRecordFromRelayAgentOverride(agentId, override) {
|
|
11449
11947
|
return normalizeLocalAgentRecord(agentId, {
|
|
11450
11948
|
definitionId: override.definitionId ?? agentId,
|
|
11451
|
-
project: override.projectName ??
|
|
11949
|
+
project: override.projectName ?? basename5(override.projectRoot || override.runtime?.cwd || agentId),
|
|
11452
11950
|
projectRoot: override.projectRoot ?? override.runtime?.cwd,
|
|
11453
11951
|
tmuxSession: override.runtime?.sessionId ?? `relay-${agentId}`,
|
|
11454
11952
|
cwd: override.runtime?.cwd ?? override.projectRoot,
|
|
@@ -11544,7 +12042,7 @@ function buildLocalAgentBootstrapPrompt(_harness, _systemPrompt, initialMessage)
|
|
|
11544
12042
|
function buildLocalAgentLaunchCommand(agentName, record, projectPath, promptFile, workerScript) {
|
|
11545
12043
|
const extraArgs = shellQuoteArguments(normalizeLaunchArgsForHarness(normalizeLocalAgentHarness(record.harness), record.launchArgs));
|
|
11546
12044
|
if (normalizeLocalAgentHarness(record.harness) === "codex") {
|
|
11547
|
-
return `exec bash ${JSON.stringify(workerScript ??
|
|
12045
|
+
return `exec bash ${JSON.stringify(workerScript ?? join12(relayAgentRuntimeDirectory(agentName), "codex-worker.sh"))}`;
|
|
11548
12046
|
}
|
|
11549
12047
|
return [
|
|
11550
12048
|
"claude",
|
|
@@ -11590,7 +12088,7 @@ async function ensureLocalAgentOnline(agentName, record) {
|
|
|
11590
12088
|
return normalizedRecord;
|
|
11591
12089
|
}
|
|
11592
12090
|
const projectPath = normalizedRecord.cwd;
|
|
11593
|
-
const projectName = normalizedRecord.project ||
|
|
12091
|
+
const projectName = normalizedRecord.project || basename5(projectPath);
|
|
11594
12092
|
const systemPromptTemplate = normalizedRecord.systemPrompt || buildLocalAgentSystemPromptTemplate();
|
|
11595
12093
|
const systemPrompt = renderLocalAgentSystemPromptTemplate(systemPromptTemplate, buildLocalAgentTemplateContext(agentName, projectName, projectPath), { transport: normalizedRecord.transport });
|
|
11596
12094
|
const agentRuntimeDir = relayAgentRuntimeDirectory(agentName);
|
|
@@ -11598,7 +12096,7 @@ async function ensureLocalAgentOnline(agentName, record) {
|
|
|
11598
12096
|
await mkdir6(agentRuntimeDir, { recursive: true });
|
|
11599
12097
|
await mkdir6(logsDir, { recursive: true });
|
|
11600
12098
|
if (normalizedRecord.transport === "codex_app_server") {
|
|
11601
|
-
await writeFile6(
|
|
12099
|
+
await writeFile6(join12(agentRuntimeDir, "prompt.txt"), systemPrompt);
|
|
11602
12100
|
await ensureCodexAppServerAgentOnline(buildCodexAgentSessionOptions(agentName, normalizedRecord, systemPrompt));
|
|
11603
12101
|
const registry2 = await readLocalAgentRegistry();
|
|
11604
12102
|
registry2[agentName] = {
|
|
@@ -11610,7 +12108,7 @@ async function ensureLocalAgentOnline(agentName, record) {
|
|
|
11610
12108
|
return registry2[agentName];
|
|
11611
12109
|
}
|
|
11612
12110
|
if (normalizedRecord.transport === "claude_stream_json") {
|
|
11613
|
-
await writeFile6(
|
|
12111
|
+
await writeFile6(join12(agentRuntimeDir, "prompt.txt"), systemPrompt);
|
|
11614
12112
|
await ensureClaudeStreamJsonAgentOnline(buildClaudeAgentSessionOptions(agentName, normalizedRecord, systemPrompt));
|
|
11615
12113
|
const registry2 = await readLocalAgentRegistry();
|
|
11616
12114
|
registry2[agentName] = {
|
|
@@ -11623,17 +12121,17 @@ async function ensureLocalAgentOnline(agentName, record) {
|
|
|
11623
12121
|
}
|
|
11624
12122
|
const initialMessage = buildLocalAgentInitialMessage(projectName, agentName);
|
|
11625
12123
|
const bootstrapPrompt = buildLocalAgentBootstrapPrompt(normalizeLocalAgentHarness(normalizedRecord.harness), systemPrompt, initialMessage);
|
|
11626
|
-
const queueDirectory =
|
|
11627
|
-
const processingDirectory =
|
|
11628
|
-
const processedDirectory =
|
|
11629
|
-
const promptFile =
|
|
11630
|
-
const initialFile =
|
|
11631
|
-
const launchScript =
|
|
11632
|
-
const workerScript =
|
|
11633
|
-
const codexSessionIdFile =
|
|
11634
|
-
const stateFile =
|
|
11635
|
-
const stdoutLogFile =
|
|
11636
|
-
const stderrLogFile =
|
|
12124
|
+
const queueDirectory = join12(agentRuntimeDir, "queue");
|
|
12125
|
+
const processingDirectory = join12(queueDirectory, "processing");
|
|
12126
|
+
const processedDirectory = join12(queueDirectory, "processed");
|
|
12127
|
+
const promptFile = join12(agentRuntimeDir, "prompt.txt");
|
|
12128
|
+
const initialFile = join12(agentRuntimeDir, "initial.txt");
|
|
12129
|
+
const launchScript = join12(agentRuntimeDir, "launch.sh");
|
|
12130
|
+
const workerScript = join12(agentRuntimeDir, "codex-worker.sh");
|
|
12131
|
+
const codexSessionIdFile = join12(agentRuntimeDir, "codex-session-id.txt");
|
|
12132
|
+
const stateFile = join12(agentRuntimeDir, "state.json");
|
|
12133
|
+
const stdoutLogFile = join12(logsDir, "stdout.log");
|
|
12134
|
+
const stderrLogFile = join12(logsDir, "stderr.log");
|
|
11637
12135
|
await writeFile6(promptFile, systemPrompt);
|
|
11638
12136
|
await writeFile6(initialFile, bootstrapPrompt);
|
|
11639
12137
|
await writeFile6(stderrLogFile, "");
|
|
@@ -11695,10 +12193,10 @@ async function ensureLocalAgentOnline(agentName, record) {
|
|
|
11695
12193
|
if (isLocalAgentSessionAlive(normalizedRecord.tmuxSession)) {
|
|
11696
12194
|
break;
|
|
11697
12195
|
}
|
|
11698
|
-
await new Promise((
|
|
12196
|
+
await new Promise((resolve9) => setTimeout(resolve9, 100));
|
|
11699
12197
|
}
|
|
11700
12198
|
if (!isLocalAgentSessionAlive(normalizedRecord.tmuxSession)) {
|
|
11701
|
-
const stderrTail =
|
|
12199
|
+
const stderrTail = existsSync9(stderrLogFile) ? readFileSync4(stderrLogFile, "utf8").trim().split(/\r?\n/).slice(-10).join(`
|
|
11702
12200
|
`).trim() : "";
|
|
11703
12201
|
throw new Error(stderrTail ? `Relay agent ${agentName} failed to stay online:
|
|
11704
12202
|
${stderrTail}` : `Relay agent ${agentName} failed to stay online.`);
|
|
@@ -11748,19 +12246,42 @@ async function restartLocalAgent(agentId, options = {}) {
|
|
|
11748
12246
|
}
|
|
11749
12247
|
return ensureLocalAgentOnline(agentId, normalizedRecord);
|
|
11750
12248
|
}
|
|
11751
|
-
|
|
12249
|
+
function resolvedAgentNameFromOverride(agentId, override) {
|
|
12250
|
+
return {
|
|
12251
|
+
agentId,
|
|
12252
|
+
definitionId: override.definitionId ?? agentId,
|
|
12253
|
+
projectRoot: override.projectRoot
|
|
12254
|
+
};
|
|
12255
|
+
}
|
|
12256
|
+
async function resolveLocalAgentByName(name, options = {}) {
|
|
11752
12257
|
const normalized = normalizeAgentSelectorSegment(name);
|
|
11753
12258
|
if (!normalized)
|
|
11754
12259
|
return null;
|
|
11755
12260
|
const overrides = await readRelayAgentOverrides();
|
|
11756
|
-
|
|
11757
|
-
|
|
11758
|
-
|
|
11759
|
-
|
|
11760
|
-
|
|
11761
|
-
|
|
12261
|
+
const entries = Object.entries(overrides).filter(([agentId]) => !BUILT_IN_AGENT_DEFINITION_IDS.has(agentId));
|
|
12262
|
+
const exactAgentIdMatch = entries.find(([agentId]) => normalizeAgentSelectorSegment(agentId) === normalized);
|
|
12263
|
+
if (exactAgentIdMatch) {
|
|
12264
|
+
return resolvedAgentNameFromOverride(exactAgentIdMatch[0], exactAgentIdMatch[1]);
|
|
12265
|
+
}
|
|
12266
|
+
const definitionMatches = entries.filter(([agentId, override]) => (override.definitionId ?? agentId) === normalized);
|
|
12267
|
+
if (definitionMatches.length === 1) {
|
|
12268
|
+
const [agentId, override] = definitionMatches[0];
|
|
12269
|
+
return resolvedAgentNameFromOverride(agentId, override);
|
|
12270
|
+
}
|
|
12271
|
+
if (definitionMatches.length > 1) {
|
|
12272
|
+
const preferredMatch = definitionMatches.find(([agentId]) => /\.(main|master)\./.test(agentId)) ?? definitionMatches[0];
|
|
12273
|
+
if (preferredMatch) {
|
|
12274
|
+
return resolvedAgentNameFromOverride(preferredMatch[0], preferredMatch[1]);
|
|
11762
12275
|
}
|
|
11763
12276
|
}
|
|
12277
|
+
if (!options.matchProjectName) {
|
|
12278
|
+
return null;
|
|
12279
|
+
}
|
|
12280
|
+
const projectMatches = entries.filter(([, override]) => normalizeAgentSelectorSegment(override.projectName ?? "") === normalized);
|
|
12281
|
+
if (projectMatches.length === 1) {
|
|
12282
|
+
const [agentId, override] = projectMatches[0];
|
|
12283
|
+
return resolvedAgentNameFromOverride(agentId, override);
|
|
12284
|
+
}
|
|
11764
12285
|
return null;
|
|
11765
12286
|
}
|
|
11766
12287
|
async function listLocalAgents(options = {}) {
|
|
@@ -11812,7 +12333,7 @@ async function resolveLocalAgentIdentity(input) {
|
|
|
11812
12333
|
nodeQualifier: instance2.nodeQualifier,
|
|
11813
12334
|
harness: normalizeManagedHarness2(preferredHarness ?? override.defaultHarness, "claude"),
|
|
11814
12335
|
projectRoot: normalizeProjectPath(override.projectRoot),
|
|
11815
|
-
projectName: override.projectName ??
|
|
12336
|
+
projectName: override.projectName ?? basename5(override.projectRoot),
|
|
11816
12337
|
source: "existing"
|
|
11817
12338
|
};
|
|
11818
12339
|
}
|
|
@@ -11831,12 +12352,12 @@ async function resolveLocalAgentIdentity(input) {
|
|
|
11831
12352
|
nodeQualifier: instance2.nodeQualifier,
|
|
11832
12353
|
harness: normalizeManagedHarness2(preferredHarness ?? override.defaultHarness, "claude"),
|
|
11833
12354
|
projectRoot: normalizeProjectPath(override.projectRoot),
|
|
11834
|
-
projectName: override.projectName ??
|
|
12355
|
+
projectName: override.projectName ?? basename5(override.projectRoot),
|
|
11835
12356
|
source: "existing"
|
|
11836
12357
|
};
|
|
11837
12358
|
}
|
|
11838
12359
|
const configDefinitionId = config?.agent?.id?.trim() ? normalizeAgentSelectorSegment(config.agent.id.trim()) : "";
|
|
11839
|
-
const definitionId = requestedDefinitionId || configDefinitionId || normalizeAgentSelectorSegment(
|
|
12360
|
+
const definitionId = requestedDefinitionId || configDefinitionId || normalizeAgentSelectorSegment(basename5(projectRoot)) || "agent";
|
|
11840
12361
|
const configDisplayName = config?.agent?.displayName?.trim() || "";
|
|
11841
12362
|
const displayName = input.displayName || configDisplayName || titleCaseLocalAgentName(definitionId);
|
|
11842
12363
|
const instance = buildRelayAgentInstance(definitionId, projectRoot);
|
|
@@ -11850,7 +12371,7 @@ async function resolveLocalAgentIdentity(input) {
|
|
|
11850
12371
|
nodeQualifier: instance.nodeQualifier,
|
|
11851
12372
|
harness: effectiveHarness,
|
|
11852
12373
|
projectRoot,
|
|
11853
|
-
projectName:
|
|
12374
|
+
projectName: basename5(projectRoot),
|
|
11854
12375
|
source: configDefinitionId || configDisplayName ? "config" : "new"
|
|
11855
12376
|
};
|
|
11856
12377
|
}
|
|
@@ -11859,6 +12380,7 @@ async function startLocalAgent(input) {
|
|
|
11859
12380
|
const preferredHarness = input.harness ? normalizeLocalAgentHarness(input.harness) : undefined;
|
|
11860
12381
|
const currentDirectory = input.currentDirectory ?? projectPath;
|
|
11861
12382
|
const effectiveCwd = input.cwdOverride ? normalizeProjectPath(input.cwdOverride) : undefined;
|
|
12383
|
+
const shouldEnsureOnline = input.ensureOnline !== false;
|
|
11862
12384
|
const requestedDefinitionId = input.agentName?.trim() ? normalizeAgentSelectorSegment(input.agentName.trim()) : "";
|
|
11863
12385
|
if (input.agentName?.trim() && !requestedDefinitionId) {
|
|
11864
12386
|
throw new Error(`Invalid agent name "${input.agentName}".`);
|
|
@@ -11906,7 +12428,7 @@ async function startLocalAgent(input) {
|
|
|
11906
12428
|
}
|
|
11907
12429
|
if (!matchingOverride) {
|
|
11908
12430
|
const configDefinitionId = coldProjectConfig?.agent?.id?.trim() ? normalizeAgentSelectorSegment(coldProjectConfig.agent.id.trim()) : "";
|
|
11909
|
-
const definitionId = requestedDefinitionId || configDefinitionId || normalizeAgentSelectorSegment(
|
|
12431
|
+
const definitionId = requestedDefinitionId || configDefinitionId || normalizeAgentSelectorSegment(basename5(projectRoot)) || "agent";
|
|
11910
12432
|
const configDisplayName = coldProjectConfig?.agent?.displayName?.trim() || "";
|
|
11911
12433
|
const effectiveDisplayName = input.displayName || configDisplayName || titleCaseLocalAgentName(definitionId);
|
|
11912
12434
|
const instance = buildRelayAgentInstance(definitionId, projectRoot);
|
|
@@ -11923,7 +12445,7 @@ async function startLocalAgent(input) {
|
|
|
11923
12445
|
agentId: instance.id,
|
|
11924
12446
|
definitionId,
|
|
11925
12447
|
displayName: effectiveDisplayName,
|
|
11926
|
-
projectName:
|
|
12448
|
+
projectName: basename5(projectRoot),
|
|
11927
12449
|
projectRoot,
|
|
11928
12450
|
projectConfigPath: coldProjectConfigPath,
|
|
11929
12451
|
source: "manual",
|
|
@@ -11963,7 +12485,7 @@ async function startLocalAgent(input) {
|
|
|
11963
12485
|
agentId: instance.id,
|
|
11964
12486
|
definitionId: requestedDefinitionId,
|
|
11965
12487
|
displayName: input.displayName || titleCaseLocalAgentName(requestedDefinitionId),
|
|
11966
|
-
projectName: matchingOverride.projectName ??
|
|
12488
|
+
projectName: matchingOverride.projectName ?? basename5(matchingProjectRoot),
|
|
11967
12489
|
projectRoot: matchingProjectRoot,
|
|
11968
12490
|
projectConfigPath: matchingOverride.projectConfigPath ?? null,
|
|
11969
12491
|
source: "manual",
|
|
@@ -12008,12 +12530,14 @@ async function startLocalAgent(input) {
|
|
|
12008
12530
|
}
|
|
12009
12531
|
targetAgentId = matchingAgentId;
|
|
12010
12532
|
}
|
|
12011
|
-
|
|
12012
|
-
|
|
12013
|
-
|
|
12014
|
-
|
|
12015
|
-
|
|
12016
|
-
|
|
12533
|
+
if (shouldEnsureOnline) {
|
|
12534
|
+
await ensureLocalAgentBindingOnline(targetAgentId, process.env.OPENSCOUT_NODE_ID ?? "local", {
|
|
12535
|
+
includeDiscovered: false,
|
|
12536
|
+
currentDirectory,
|
|
12537
|
+
ensureCurrentProjectConfig: false,
|
|
12538
|
+
harness: preferredHarness
|
|
12539
|
+
});
|
|
12540
|
+
}
|
|
12017
12541
|
const finalOverrides = await readRelayAgentOverrides();
|
|
12018
12542
|
const finalOverride = finalOverrides[targetAgentId];
|
|
12019
12543
|
if (!finalOverride) {
|
|
@@ -12096,8 +12620,8 @@ async function restartAllLocalAgents(options = {}) {
|
|
|
12096
12620
|
function readPersistedClaudeSessionId(agentName) {
|
|
12097
12621
|
try {
|
|
12098
12622
|
const runtimeDir = relayAgentRuntimeDirectory(agentName);
|
|
12099
|
-
const catalogPath =
|
|
12100
|
-
if (
|
|
12623
|
+
const catalogPath = join12(runtimeDir, "session-catalog.json");
|
|
12624
|
+
if (existsSync9(catalogPath)) {
|
|
12101
12625
|
const raw = readFileSync4(catalogPath, "utf8").trim();
|
|
12102
12626
|
if (raw) {
|
|
12103
12627
|
const catalog = JSON.parse(raw);
|
|
@@ -12106,8 +12630,8 @@ function readPersistedClaudeSessionId(agentName) {
|
|
|
12106
12630
|
}
|
|
12107
12631
|
}
|
|
12108
12632
|
}
|
|
12109
|
-
const legacyPath =
|
|
12110
|
-
if (
|
|
12633
|
+
const legacyPath = join12(runtimeDir, "claude-session-id.txt");
|
|
12634
|
+
if (existsSync9(legacyPath)) {
|
|
12111
12635
|
const value = readFileSync4(legacyPath, "utf8").trim();
|
|
12112
12636
|
return value || null;
|
|
12113
12637
|
}
|
|
@@ -12295,22 +12819,22 @@ var init_local_agents = __esm(async () => {
|
|
|
12295
12819
|
init_support_paths();
|
|
12296
12820
|
init_local_agent_template();
|
|
12297
12821
|
await init_broker_service();
|
|
12298
|
-
MODULE_DIRECTORY =
|
|
12299
|
-
OPENSCOUT_REPO_ROOT =
|
|
12822
|
+
MODULE_DIRECTORY = dirname7(fileURLToPath6(import.meta.url));
|
|
12823
|
+
OPENSCOUT_REPO_ROOT = resolve8(MODULE_DIRECTORY, "..", "..", "..");
|
|
12300
12824
|
DEFAULT_LOCAL_AGENT_CAPABILITIES = ["chat", "invoke", "deliver"];
|
|
12301
12825
|
SUPPORTED_LOCAL_AGENT_HARNESSES = ["claude", "codex"];
|
|
12302
12826
|
});
|
|
12303
12827
|
|
|
12304
12828
|
// ../runtime/src/user-config.ts
|
|
12305
|
-
import { existsSync as
|
|
12306
|
-
import { homedir as
|
|
12307
|
-
import { dirname as
|
|
12829
|
+
import { existsSync as existsSync10, readFileSync as readFileSync5, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "fs";
|
|
12830
|
+
import { homedir as homedir9 } from "os";
|
|
12831
|
+
import { dirname as dirname8, join as join13 } from "path";
|
|
12308
12832
|
function userConfigPath() {
|
|
12309
|
-
return
|
|
12833
|
+
return join13(process.env.OPENSCOUT_HOME ?? join13(homedir9(), ".openscout"), "user.json");
|
|
12310
12834
|
}
|
|
12311
12835
|
function loadUserConfig() {
|
|
12312
12836
|
const configPath = userConfigPath();
|
|
12313
|
-
if (!
|
|
12837
|
+
if (!existsSync10(configPath))
|
|
12314
12838
|
return {};
|
|
12315
12839
|
try {
|
|
12316
12840
|
return JSON.parse(readFileSync5(configPath, "utf8"));
|
|
@@ -12320,7 +12844,7 @@ function loadUserConfig() {
|
|
|
12320
12844
|
}
|
|
12321
12845
|
function saveUserConfig(config) {
|
|
12322
12846
|
const configPath = userConfigPath();
|
|
12323
|
-
mkdirSync3(
|
|
12847
|
+
mkdirSync3(dirname8(configPath), { recursive: true });
|
|
12324
12848
|
writeFileSync3(configPath, JSON.stringify(config, null, 2) + `
|
|
12325
12849
|
`, "utf8");
|
|
12326
12850
|
}
|
|
@@ -12350,6 +12874,7 @@ var init_paths = __esm(() => {
|
|
|
12350
12874
|
endpoints: "/v1/endpoints",
|
|
12351
12875
|
conversations: "/v1/conversations",
|
|
12352
12876
|
invocations: "/v1/invocations",
|
|
12877
|
+
deliver: "/v1/deliver",
|
|
12353
12878
|
activity: "/v1/activity",
|
|
12354
12879
|
collaborationRecords: "/v1/collaboration/records",
|
|
12355
12880
|
collaborationEvents: "/v1/collaboration/events"
|
|
@@ -12358,8 +12883,8 @@ var init_paths = __esm(() => {
|
|
|
12358
12883
|
});
|
|
12359
12884
|
|
|
12360
12885
|
// ../../apps/desktop/src/core/broker/service.ts
|
|
12361
|
-
import { mkdir as mkdir7, readFile as
|
|
12362
|
-
import { basename as
|
|
12886
|
+
import { mkdir as mkdir7, readFile as readFile8, unlink, writeFile as writeFile7 } from "fs/promises";
|
|
12887
|
+
import { basename as basename6, join as join14, resolve as resolve9 } from "path";
|
|
12363
12888
|
function buildScoutBrokerUrlFromEnv() {
|
|
12364
12889
|
const host = process.env.OPENSCOUT_BROKER_HOST ?? DEFAULT_BROKER_HOST2;
|
|
12365
12890
|
const port = Number.parseInt(process.env.OPENSCOUT_BROKER_PORT ?? String(DEFAULT_BROKER_PORT2), 10);
|
|
@@ -12385,7 +12910,8 @@ function resolveScoutAgentName(agentName) {
|
|
|
12385
12910
|
}
|
|
12386
12911
|
return resolveOperatorName();
|
|
12387
12912
|
}
|
|
12388
|
-
function resolveConfiguredSenderIdForProjectRoot(overrides, projectRoot) {
|
|
12913
|
+
function resolveConfiguredSenderIdForProjectRoot(overrides, projectRoot, preferredDefinitionId) {
|
|
12914
|
+
let fallbackSenderId = null;
|
|
12389
12915
|
for (const [agentId, override] of Object.entries(overrides)) {
|
|
12390
12916
|
if (BUILT_IN_AGENT_DEFINITION_IDS.has(agentId)) {
|
|
12391
12917
|
continue;
|
|
@@ -12393,19 +12919,22 @@ function resolveConfiguredSenderIdForProjectRoot(overrides, projectRoot) {
|
|
|
12393
12919
|
if (!override.projectRoot || override.projectRoot !== projectRoot) {
|
|
12394
12920
|
continue;
|
|
12395
12921
|
}
|
|
12396
|
-
|
|
12922
|
+
if (preferredDefinitionId && override.definitionId === preferredDefinitionId) {
|
|
12923
|
+
return agentId;
|
|
12924
|
+
}
|
|
12925
|
+
fallbackSenderId ??= agentId;
|
|
12397
12926
|
}
|
|
12398
|
-
return
|
|
12927
|
+
return fallbackSenderId;
|
|
12399
12928
|
}
|
|
12400
12929
|
async function inferSenderIdForProjectRoot(projectRoot) {
|
|
12401
12930
|
const overrides = await readRelayAgentOverrides();
|
|
12402
|
-
const
|
|
12931
|
+
const projectConfig = await readProjectConfig(projectRoot);
|
|
12932
|
+
const configuredDefinitionId = normalizeAgentSelectorSegment(projectConfig?.agent?.id?.trim() ?? "");
|
|
12933
|
+
const configuredSenderId = resolveConfiguredSenderIdForProjectRoot(overrides, projectRoot, configuredDefinitionId);
|
|
12403
12934
|
if (configuredSenderId) {
|
|
12404
12935
|
return configuredSenderId;
|
|
12405
12936
|
}
|
|
12406
|
-
const
|
|
12407
|
-
const configuredDefinitionId = normalizeAgentSelectorSegment(projectConfig?.agent?.id?.trim() ?? "");
|
|
12408
|
-
const definitionId = configuredDefinitionId || normalizeAgentSelectorSegment(basename5(projectRoot)) || "agent";
|
|
12937
|
+
const definitionId = configuredDefinitionId || normalizeAgentSelectorSegment(basename6(projectRoot)) || "agent";
|
|
12409
12938
|
return buildRelayAgentInstance(definitionId, projectRoot).id;
|
|
12410
12939
|
}
|
|
12411
12940
|
async function resolveScoutSenderId(agentName, currentDirectory, env = process.env) {
|
|
@@ -12523,6 +13052,51 @@ async function brokerPostJson(baseUrl, path, body) {
|
|
|
12523
13052
|
}
|
|
12524
13053
|
return response.json();
|
|
12525
13054
|
}
|
|
13055
|
+
function renderScoutTargetLabel(targetLabel) {
|
|
13056
|
+
const trimmed = targetLabel.trim();
|
|
13057
|
+
if (!trimmed) {
|
|
13058
|
+
return "";
|
|
13059
|
+
}
|
|
13060
|
+
return trimmed.startsWith("@") ? trimmed : `@${trimmed}`;
|
|
13061
|
+
}
|
|
13062
|
+
function scoutTargetDiagnosticFromDeliveryFailure(delivery) {
|
|
13063
|
+
const dispatch = delivery.kind === "question" ? delivery.question : delivery.rejection;
|
|
13064
|
+
if (dispatch.kind === "ambiguous") {
|
|
13065
|
+
return {
|
|
13066
|
+
state: "ambiguous",
|
|
13067
|
+
candidates: dispatch.candidates.map((candidate) => ({
|
|
13068
|
+
agentId: candidate.agentId,
|
|
13069
|
+
label: candidate.label
|
|
13070
|
+
}))
|
|
13071
|
+
};
|
|
13072
|
+
}
|
|
13073
|
+
if (dispatch.kind === "unavailable" && dispatch.target) {
|
|
13074
|
+
return {
|
|
13075
|
+
agentId: dispatch.target.agentId,
|
|
13076
|
+
state: "unavailable",
|
|
13077
|
+
detail: dispatch.target.detail,
|
|
13078
|
+
wakePolicy: dispatch.target.wakePolicy ?? null,
|
|
13079
|
+
transport: dispatch.target.transport ?? null,
|
|
13080
|
+
projectRoot: dispatch.target.projectRoot ?? null
|
|
13081
|
+
};
|
|
13082
|
+
}
|
|
13083
|
+
if (dispatch.kind === "unknown") {
|
|
13084
|
+
return {
|
|
13085
|
+
agentId: dispatch.askedLabel,
|
|
13086
|
+
state: "unknown",
|
|
13087
|
+
registrationKind: null,
|
|
13088
|
+
projectRoot: null
|
|
13089
|
+
};
|
|
13090
|
+
}
|
|
13091
|
+
if (delivery.kind === "rejected" && dispatch.kind === "unparseable") {
|
|
13092
|
+
return {
|
|
13093
|
+
state: delivery.reason === "missing_target" ? "missing" : "invalid",
|
|
13094
|
+
askedLabel: dispatch.askedLabel,
|
|
13095
|
+
detail: dispatch.detail
|
|
13096
|
+
};
|
|
13097
|
+
}
|
|
13098
|
+
return;
|
|
13099
|
+
}
|
|
12526
13100
|
async function readScoutBrokerHealth(baseUrl = resolveScoutBrokerUrl()) {
|
|
12527
13101
|
try {
|
|
12528
13102
|
const health = await brokerReadJson(baseUrl, scoutBrokerPaths.health);
|
|
@@ -12616,84 +13190,6 @@ function formatBrokerTargetLabel(snapshot, agentId) {
|
|
|
12616
13190
|
const candidate = buildMentionCandidate(snapshot, current);
|
|
12617
13191
|
return formatMinimalAgentIdentity(candidate, candidates);
|
|
12618
13192
|
}
|
|
12619
|
-
function normalizeProjectLocalResolutionValue(value) {
|
|
12620
|
-
return value?.trim().toLowerCase().replace(/^@+/, "") ?? "";
|
|
12621
|
-
}
|
|
12622
|
-
function matchesObviousProjectLocalAlias(value, query) {
|
|
12623
|
-
const normalized = normalizeProjectLocalResolutionValue(value);
|
|
12624
|
-
if (!normalized || !query) {
|
|
12625
|
-
return false;
|
|
12626
|
-
}
|
|
12627
|
-
return normalized === query || normalized.startsWith(`${query}-`) || normalized.startsWith(`${query}.`) || normalized.startsWith(`${query}_`) || normalized.startsWith(`${query} `);
|
|
12628
|
-
}
|
|
12629
|
-
function agentProjectRoot(snapshot, agentId) {
|
|
12630
|
-
const endpoints = Object.values(snapshot.endpoints).filter((endpoint) => endpoint.agentId === agentId);
|
|
12631
|
-
const preferred = endpoints.find((endpoint) => endpoint.state === "active") ?? endpoints.find((endpoint) => endpoint.state === "idle" || endpoint.state === "waiting") ?? endpoints[0];
|
|
12632
|
-
return preferred?.projectRoot ?? preferred?.cwd ?? metadataString2(snapshot.agents[agentId]?.metadata, "projectRoot") ?? null;
|
|
12633
|
-
}
|
|
12634
|
-
function agentPreferredState(snapshot, agentId) {
|
|
12635
|
-
const endpoints = Object.values(snapshot.endpoints).filter((endpoint) => endpoint.agentId === agentId);
|
|
12636
|
-
const preferred = endpoints.find((endpoint) => endpoint.state === "active") ?? endpoints.find((endpoint) => endpoint.state === "idle" || endpoint.state === "waiting") ?? endpoints[0];
|
|
12637
|
-
return preferred?.state ?? "offline";
|
|
12638
|
-
}
|
|
12639
|
-
function scoreProjectLocalBrokerAgent(snapshot, agentId, currentProjectRoot, query) {
|
|
12640
|
-
const projectRoot = agentProjectRoot(snapshot, agentId);
|
|
12641
|
-
if (!projectRoot || resolve8(projectRoot) !== resolve8(currentProjectRoot)) {
|
|
12642
|
-
return -1;
|
|
12643
|
-
}
|
|
12644
|
-
const agent = snapshot.agents[agentId];
|
|
12645
|
-
const formattedLabel = formatBrokerTargetLabel(snapshot, agentId);
|
|
12646
|
-
const values = [
|
|
12647
|
-
formattedLabel,
|
|
12648
|
-
agent?.defaultSelector,
|
|
12649
|
-
agent?.selector,
|
|
12650
|
-
agent?.handle,
|
|
12651
|
-
agent?.displayName,
|
|
12652
|
-
agent?.definitionId,
|
|
12653
|
-
agentId
|
|
12654
|
-
];
|
|
12655
|
-
const matches = values.filter((value) => matchesObviousProjectLocalAlias(value, query));
|
|
12656
|
-
if (matches.length === 0) {
|
|
12657
|
-
return -1;
|
|
12658
|
-
}
|
|
12659
|
-
return 1000 + whoStateRank(agentPreferredState(snapshot, agentId)) * 20;
|
|
12660
|
-
}
|
|
12661
|
-
async function findPreferredProjectLocalBrokerTarget(snapshot, label, currentDirectory) {
|
|
12662
|
-
const query = normalizeProjectLocalResolutionValue(label);
|
|
12663
|
-
if (!query) {
|
|
12664
|
-
return null;
|
|
12665
|
-
}
|
|
12666
|
-
const currentProjectRoot = await findNearestProjectRoot(currentDirectory) ?? currentDirectory;
|
|
12667
|
-
const scored = Object.values(snapshot.agents).filter((agent) => agent.id !== OPERATOR_ID).filter((agent) => !isSupersededBrokerAgent(snapshot, agent.id)).map((agent) => ({
|
|
12668
|
-
agentId: agent.id,
|
|
12669
|
-
score: scoreProjectLocalBrokerAgent(snapshot, agent.id, currentProjectRoot, query)
|
|
12670
|
-
})).filter((entry) => entry.score >= 0).sort((left, right) => {
|
|
12671
|
-
const scoreDelta = right.score - left.score;
|
|
12672
|
-
if (scoreDelta !== 0)
|
|
12673
|
-
return scoreDelta;
|
|
12674
|
-
return left.agentId.localeCompare(right.agentId);
|
|
12675
|
-
});
|
|
12676
|
-
if (scored.length === 0) {
|
|
12677
|
-
return null;
|
|
12678
|
-
}
|
|
12679
|
-
if (scored.length > 1 && scored[0]?.score === scored[1]?.score) {
|
|
12680
|
-
return null;
|
|
12681
|
-
}
|
|
12682
|
-
const agentId = scored[0]?.agentId;
|
|
12683
|
-
if (!agentId) {
|
|
12684
|
-
return null;
|
|
12685
|
-
}
|
|
12686
|
-
const resolvedLabel = formatBrokerTargetLabel(snapshot, agentId);
|
|
12687
|
-
const selector = extractAgentSelectors(resolvedLabel)[0];
|
|
12688
|
-
if (!selector) {
|
|
12689
|
-
return null;
|
|
12690
|
-
}
|
|
12691
|
-
return {
|
|
12692
|
-
agentId,
|
|
12693
|
-
label: resolvedLabel,
|
|
12694
|
-
selector
|
|
12695
|
-
};
|
|
12696
|
-
}
|
|
12697
13193
|
async function resolveMentionTargets(snapshot, text, currentDirectory) {
|
|
12698
13194
|
const mentions = extractAgentMentions(text);
|
|
12699
13195
|
const selectors = mentions.parsed;
|
|
@@ -12764,55 +13260,6 @@ async function resolveMentionTargets(snapshot, text, currentDirectory) {
|
|
|
12764
13260
|
ambiguous
|
|
12765
13261
|
};
|
|
12766
13262
|
}
|
|
12767
|
-
async function resolveSingleBrokerTarget(snapshot, label, currentDirectory) {
|
|
12768
|
-
const normalized = label.trim();
|
|
12769
|
-
if (!normalized) {
|
|
12770
|
-
return { kind: "unresolved" };
|
|
12771
|
-
}
|
|
12772
|
-
const resolution = await resolveMentionTargets(snapshot, normalized.startsWith("@") ? normalized : `@${normalized}`, currentDirectory);
|
|
12773
|
-
const preferredProjectLocalTarget = await findPreferredProjectLocalBrokerTarget(snapshot, normalized, currentDirectory);
|
|
12774
|
-
if (preferredProjectLocalTarget) {
|
|
12775
|
-
return { kind: "resolved", target: preferredProjectLocalTarget };
|
|
12776
|
-
}
|
|
12777
|
-
const firstAmbiguous = resolution.ambiguous[0];
|
|
12778
|
-
if (firstAmbiguous) {
|
|
12779
|
-
return { kind: "ambiguous", candidates: firstAmbiguous.candidates };
|
|
12780
|
-
}
|
|
12781
|
-
const first = resolution.resolved[0];
|
|
12782
|
-
if (first) {
|
|
12783
|
-
return { kind: "resolved", target: first };
|
|
12784
|
-
}
|
|
12785
|
-
return { kind: "unresolved" };
|
|
12786
|
-
}
|
|
12787
|
-
async function describeScoutTargetAvailability(snapshot, target, currentDirectory) {
|
|
12788
|
-
const resolvedConfig = await resolveRelayAgentConfig(target.selector, {
|
|
12789
|
-
currentDirectory
|
|
12790
|
-
});
|
|
12791
|
-
const registrationKind = resolvedConfig?.registrationKind ?? null;
|
|
12792
|
-
const endpoints = Object.values(snapshot.endpoints ?? {}).filter((endpoint) => endpoint.agentId === target.agentId);
|
|
12793
|
-
if (endpoints.length > 0) {
|
|
12794
|
-
return {
|
|
12795
|
-
agentId: target.agentId,
|
|
12796
|
-
state: whoEntryState(endpoints, registrationKind ?? "broker"),
|
|
12797
|
-
registrationKind,
|
|
12798
|
-
projectRoot: resolvedConfig?.projectRoot ?? null
|
|
12799
|
-
};
|
|
12800
|
-
}
|
|
12801
|
-
if (registrationKind === "discovered") {
|
|
12802
|
-
return {
|
|
12803
|
-
agentId: target.agentId,
|
|
12804
|
-
state: "discovered",
|
|
12805
|
-
registrationKind,
|
|
12806
|
-
projectRoot: resolvedConfig?.projectRoot ?? null
|
|
12807
|
-
};
|
|
12808
|
-
}
|
|
12809
|
-
return {
|
|
12810
|
-
agentId: target.agentId,
|
|
12811
|
-
state: snapshot.agents[target.agentId] || registrationKind === "configured" ? "offline" : "unknown",
|
|
12812
|
-
registrationKind,
|
|
12813
|
-
projectRoot: resolvedConfig?.projectRoot ?? null
|
|
12814
|
-
};
|
|
12815
|
-
}
|
|
12816
13263
|
function resolveConversationShareMode(snapshot, nodeId, participantIds, fallback) {
|
|
12817
13264
|
if (fallback === "shared")
|
|
12818
13265
|
return "shared";
|
|
@@ -13318,72 +13765,74 @@ async function sendScoutMessage(input) {
|
|
|
13318
13765
|
const currentDirectory = input.currentDirectory ?? process.cwd();
|
|
13319
13766
|
const createdAtMs = input.createdAtMs ?? Date.now();
|
|
13320
13767
|
const senderId = await resolveConversationActorId(broker.baseUrl, broker.snapshot, broker.node.id, input.senderId, currentDirectory);
|
|
13768
|
+
const mentionResolution = await resolveMentionTargets(broker.snapshot, input.body, currentDirectory);
|
|
13769
|
+
const selectors = extractAgentSelectors(input.body);
|
|
13321
13770
|
const requestedTargetLabel = input.targetLabel?.trim();
|
|
13322
13771
|
if (requestedTargetLabel) {
|
|
13323
|
-
const
|
|
13324
|
-
|
|
13772
|
+
const delivery = await brokerPostJson(broker.baseUrl, scoutBrokerPaths.v1.deliver, {
|
|
13773
|
+
id: `deliver-${createdAtMs.toString(36)}-${Math.random().toString(36).slice(2, 8)}`,
|
|
13774
|
+
requesterId: senderId,
|
|
13775
|
+
requesterNodeId: broker.node.id,
|
|
13776
|
+
targetLabel: requestedTargetLabel,
|
|
13777
|
+
body: input.body,
|
|
13778
|
+
intent: "tell",
|
|
13779
|
+
channel: input.channel,
|
|
13780
|
+
speechText: input.shouldSpeak ? stripScoutAgentSelectorLabels(input.body) : undefined,
|
|
13781
|
+
createdAt: createdAtMs,
|
|
13782
|
+
messageMetadata: {
|
|
13783
|
+
source: "scout-cli"
|
|
13784
|
+
}
|
|
13785
|
+
});
|
|
13786
|
+
if (delivery.kind !== "delivery") {
|
|
13325
13787
|
return {
|
|
13326
13788
|
usedBroker: true,
|
|
13327
13789
|
invokedTargets: [],
|
|
13328
|
-
unresolvedTargets: [requestedTargetLabel]
|
|
13790
|
+
unresolvedTargets: [requestedTargetLabel],
|
|
13791
|
+
targetDiagnostic: scoutTargetDiagnosticFromDeliveryFailure(delivery)
|
|
13329
13792
|
};
|
|
13330
13793
|
}
|
|
13331
|
-
|
|
13332
|
-
|
|
13333
|
-
|
|
13794
|
+
return {
|
|
13795
|
+
usedBroker: true,
|
|
13796
|
+
conversationId: delivery.conversation.id,
|
|
13797
|
+
messageId: delivery.message.id,
|
|
13798
|
+
invokedTargets: delivery.targetAgentId ? [delivery.targetAgentId] : [],
|
|
13799
|
+
unresolvedTargets: [],
|
|
13800
|
+
routeKind: delivery.routeKind
|
|
13801
|
+
};
|
|
13802
|
+
}
|
|
13803
|
+
if (selectors.length === 1 && mentionResolution.resolved.length + mentionResolution.unresolved.length + mentionResolution.ambiguous.length === 1) {
|
|
13804
|
+
const targetLabel = selectors[0].label;
|
|
13805
|
+
const delivery = await brokerPostJson(broker.baseUrl, scoutBrokerPaths.v1.deliver, {
|
|
13806
|
+
id: `deliver-${createdAtMs.toString(36)}-${Math.random().toString(36).slice(2, 8)}`,
|
|
13807
|
+
requesterId: senderId,
|
|
13808
|
+
requesterNodeId: broker.node.id,
|
|
13809
|
+
targetLabel,
|
|
13810
|
+
body: input.body,
|
|
13811
|
+
intent: "tell",
|
|
13812
|
+
channel: input.channel,
|
|
13813
|
+
speechText: input.shouldSpeak ? stripScoutAgentSelectorLabels(input.body) : undefined,
|
|
13814
|
+
createdAt: createdAtMs,
|
|
13815
|
+
messageMetadata: {
|
|
13816
|
+
source: "scout-cli"
|
|
13817
|
+
}
|
|
13818
|
+
});
|
|
13819
|
+
if (delivery.kind !== "delivery") {
|
|
13334
13820
|
return {
|
|
13335
13821
|
usedBroker: true,
|
|
13336
13822
|
invokedTargets: [],
|
|
13337
|
-
unresolvedTargets: [
|
|
13823
|
+
unresolvedTargets: [targetLabel],
|
|
13824
|
+
targetDiagnostic: scoutTargetDiagnosticFromDeliveryFailure(delivery)
|
|
13338
13825
|
};
|
|
13339
13826
|
}
|
|
13340
|
-
let conversation2;
|
|
13341
|
-
if (!input.channel) {
|
|
13342
|
-
const dm = await ensureBrokerDirectConversationBetween(broker.baseUrl, broker.snapshot, broker.node.id, senderId, target.agentId);
|
|
13343
|
-
conversation2 = dm.conversation;
|
|
13344
|
-
} else {
|
|
13345
|
-
conversation2 = await ensureBrokerConversation(broker.baseUrl, broker.snapshot, broker.node.id, input.channel, senderId, [target.agentId]);
|
|
13346
|
-
}
|
|
13347
|
-
const messageId2 = `m-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;
|
|
13348
|
-
const speechText2 = input.shouldSpeak ? stripScoutAgentSelectorLabels(input.body) : "";
|
|
13349
|
-
const returnAddress2 = buildScoutReturnAddress2(broker.snapshot, senderId, {
|
|
13350
|
-
conversationId: conversation2.id,
|
|
13351
|
-
replyToMessageId: messageId2
|
|
13352
|
-
});
|
|
13353
|
-
await brokerPostJson(broker.baseUrl, scoutBrokerPaths.v1.messages, {
|
|
13354
|
-
id: messageId2,
|
|
13355
|
-
conversationId: conversation2.id,
|
|
13356
|
-
actorId: senderId,
|
|
13357
|
-
originNodeId: broker.node.id,
|
|
13358
|
-
class: conversation2.kind === "system" ? "system" : "agent",
|
|
13359
|
-
body: input.body,
|
|
13360
|
-
mentions: [{ actorId: target.agentId, label: target.label }],
|
|
13361
|
-
speech: speechText2 ? { text: speechText2 } : undefined,
|
|
13362
|
-
audience: {
|
|
13363
|
-
notify: [target.agentId],
|
|
13364
|
-
reason: relayAudienceReason(conversation2)
|
|
13365
|
-
},
|
|
13366
|
-
visibility: conversation2.visibility,
|
|
13367
|
-
policy: "durable",
|
|
13368
|
-
createdAt: createdAtMs,
|
|
13369
|
-
metadata: {
|
|
13370
|
-
source: "scout-cli",
|
|
13371
|
-
relayChannel: relayChannelMetadata(conversation2, input.channel),
|
|
13372
|
-
relayTargetIds: [target.agentId],
|
|
13373
|
-
relayMessageId: messageId2,
|
|
13374
|
-
returnAddress: returnAddress2
|
|
13375
|
-
}
|
|
13376
|
-
});
|
|
13377
13827
|
return {
|
|
13378
13828
|
usedBroker: true,
|
|
13379
|
-
conversationId:
|
|
13380
|
-
messageId:
|
|
13381
|
-
invokedTargets: [
|
|
13829
|
+
conversationId: delivery.conversation.id,
|
|
13830
|
+
messageId: delivery.message.id,
|
|
13831
|
+
invokedTargets: delivery.targetAgentId ? [delivery.targetAgentId] : [],
|
|
13382
13832
|
unresolvedTargets: [],
|
|
13383
|
-
routeKind:
|
|
13833
|
+
routeKind: delivery.routeKind
|
|
13384
13834
|
};
|
|
13385
13835
|
}
|
|
13386
|
-
const mentionResolution = await resolveMentionTargets(broker.snapshot, input.body, currentDirectory);
|
|
13387
13836
|
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));
|
|
13388
13837
|
const validTargets = [
|
|
13389
13838
|
...new Set(availableTargets.map((target) => target.agentId).filter((target) => target !== senderId && Boolean(broker.snapshot.agents[target])))
|
|
@@ -13560,74 +14009,42 @@ async function openScoutPeerSession(input) {
|
|
|
13560
14009
|
};
|
|
13561
14010
|
}
|
|
13562
14011
|
async function sendScoutDirectMessage(input) {
|
|
13563
|
-
const currentDirectory = input.currentDirectory ?? process.cwd();
|
|
13564
|
-
const directSession = await openScoutPeerSession({
|
|
13565
|
-
sourceId: OPERATOR_ID,
|
|
13566
|
-
targetId: input.agentId,
|
|
13567
|
-
currentDirectory
|
|
13568
|
-
});
|
|
13569
14012
|
const broker = await requireScoutBrokerContext();
|
|
13570
14013
|
const createdAt = Date.now();
|
|
13571
|
-
const messageId = `msg-${createdAt.toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
13572
14014
|
const source = input.source?.trim() || "scout-mobile";
|
|
13573
|
-
const
|
|
13574
|
-
|
|
13575
|
-
|
|
13576
|
-
|
|
13577
|
-
|
|
13578
|
-
replyToMessageId: messageId
|
|
13579
|
-
});
|
|
13580
|
-
await brokerPostJson(broker.baseUrl, scoutBrokerPaths.v1.messages, {
|
|
13581
|
-
id: messageId,
|
|
13582
|
-
conversationId: directSession.conversation.id,
|
|
13583
|
-
replyToMessageId: input.replyToMessageId ?? undefined,
|
|
13584
|
-
actorId: OPERATOR_ID,
|
|
13585
|
-
originNodeId: broker.node.id,
|
|
13586
|
-
class: "agent",
|
|
14015
|
+
const delivery = await brokerPostJson(broker.baseUrl, scoutBrokerPaths.v1.deliver, {
|
|
14016
|
+
id: `deliver-${createdAt.toString(36)}-${Math.random().toString(36).slice(2, 8)}`,
|
|
14017
|
+
requesterId: OPERATOR_ID,
|
|
14018
|
+
requesterNodeId: broker.node.id,
|
|
14019
|
+
targetAgentId: input.agentId,
|
|
13587
14020
|
body: input.body.trim(),
|
|
13588
|
-
|
|
13589
|
-
|
|
13590
|
-
|
|
13591
|
-
|
|
13592
|
-
},
|
|
13593
|
-
visibility: "private",
|
|
13594
|
-
policy: "durable",
|
|
14021
|
+
intent: "consult",
|
|
14022
|
+
replyToMessageId: input.replyToMessageId ?? undefined,
|
|
14023
|
+
execution: input.executionHarness ? { harness: input.executionHarness } : undefined,
|
|
14024
|
+
ensureAwake: true,
|
|
13595
14025
|
createdAt,
|
|
13596
|
-
|
|
14026
|
+
messageMetadata: {
|
|
13597
14027
|
source,
|
|
13598
14028
|
destinationKind: "direct",
|
|
13599
|
-
destinationId:
|
|
14029
|
+
destinationId: input.agentId,
|
|
13600
14030
|
referenceMessageIds: input.referenceMessageIds ?? [],
|
|
13601
14031
|
clientMessageId: input.clientMessageId ?? null,
|
|
13602
|
-
returnAddress,
|
|
13603
14032
|
...input.deviceId ? { deviceId: input.deviceId } : {}
|
|
13604
|
-
}
|
|
13605
|
-
|
|
13606
|
-
const invocationResponse = await brokerPostJson(broker.baseUrl, scoutBrokerPaths.v1.invocations, {
|
|
13607
|
-
id: `inv-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`,
|
|
13608
|
-
requesterId: OPERATOR_ID,
|
|
13609
|
-
requesterNodeId: broker.node.id,
|
|
13610
|
-
targetAgentId,
|
|
13611
|
-
action: "consult",
|
|
13612
|
-
task: input.body.trim(),
|
|
13613
|
-
conversationId: directSession.conversation.id,
|
|
13614
|
-
messageId,
|
|
13615
|
-
execution: input.executionHarness ? { harness: input.executionHarness } : undefined,
|
|
13616
|
-
ensureAwake: true,
|
|
13617
|
-
stream: false,
|
|
13618
|
-
createdAt,
|
|
13619
|
-
metadata: {
|
|
14033
|
+
},
|
|
14034
|
+
invocationMetadata: {
|
|
13620
14035
|
source,
|
|
13621
14036
|
destinationKind: "direct",
|
|
13622
|
-
destinationId:
|
|
13623
|
-
returnAddress,
|
|
14037
|
+
destinationId: input.agentId,
|
|
13624
14038
|
...input.deviceId ? { deviceId: input.deviceId } : {}
|
|
13625
14039
|
}
|
|
13626
14040
|
});
|
|
14041
|
+
if (delivery.kind !== "delivery") {
|
|
14042
|
+
throw new Error(delivery.kind === "question" ? delivery.question.detail : delivery.rejection.detail);
|
|
14043
|
+
}
|
|
13627
14044
|
return {
|
|
13628
|
-
conversationId:
|
|
13629
|
-
messageId,
|
|
13630
|
-
flight:
|
|
14045
|
+
conversationId: delivery.conversation.id,
|
|
14046
|
+
messageId: delivery.message.id,
|
|
14047
|
+
flight: delivery.flight
|
|
13631
14048
|
};
|
|
13632
14049
|
}
|
|
13633
14050
|
async function askScoutAgentById(input) {
|
|
@@ -13643,103 +14060,46 @@ async function askScoutAgentById(input) {
|
|
|
13643
14060
|
if (!targetAgentId) {
|
|
13644
14061
|
return { usedBroker: true, unresolvedTargetId: input.targetAgentId };
|
|
13645
14062
|
}
|
|
13646
|
-
const
|
|
13647
|
-
|
|
13648
|
-
|
|
13649
|
-
|
|
13650
|
-
|
|
13651
|
-
|
|
13652
|
-
|
|
13653
|
-
|
|
13654
|
-
|
|
13655
|
-
|
|
13656
|
-
|
|
13657
|
-
|
|
13658
|
-
|
|
13659
|
-
|
|
13660
|
-
}
|
|
13661
|
-
|
|
13662
|
-
|
|
13663
|
-
|
|
14063
|
+
const delivery = await brokerPostJson(broker.baseUrl, scoutBrokerPaths.v1.deliver, {
|
|
14064
|
+
id: `deliver-${createdAtMs.toString(36)}-${Math.random().toString(36).slice(2, 8)}`,
|
|
14065
|
+
requesterId: senderId,
|
|
14066
|
+
requesterNodeId: broker.node.id,
|
|
14067
|
+
targetAgentId,
|
|
14068
|
+
body: input.body.trim(),
|
|
14069
|
+
intent: "consult",
|
|
14070
|
+
channel: input.channel,
|
|
14071
|
+
speechText: input.shouldSpeak ? input.body.trim() : undefined,
|
|
14072
|
+
execution: input.executionHarness ? { harness: input.executionHarness } : undefined,
|
|
14073
|
+
ensureAwake: true,
|
|
14074
|
+
createdAt: createdAtMs,
|
|
14075
|
+
messageMetadata: {
|
|
14076
|
+
source
|
|
14077
|
+
},
|
|
14078
|
+
invocationMetadata: {
|
|
14079
|
+
source
|
|
14080
|
+
}
|
|
14081
|
+
});
|
|
14082
|
+
if (delivery.kind !== "delivery") {
|
|
13664
14083
|
return {
|
|
13665
14084
|
usedBroker: true,
|
|
13666
14085
|
unresolvedTargetId: targetAgentId,
|
|
13667
|
-
targetDiagnostic:
|
|
14086
|
+
targetDiagnostic: scoutTargetDiagnosticFromDeliveryFailure(delivery)
|
|
13668
14087
|
};
|
|
13669
14088
|
}
|
|
13670
|
-
let conversation;
|
|
13671
|
-
if (!input.channel) {
|
|
13672
|
-
const dm = await ensureBrokerDirectConversationBetween(broker.baseUrl, broker.snapshot, broker.node.id, senderId, targetAgentId);
|
|
13673
|
-
conversation = dm.conversation;
|
|
13674
|
-
} else {
|
|
13675
|
-
conversation = await ensureBrokerConversation(broker.baseUrl, broker.snapshot, broker.node.id, input.channel, senderId, [targetAgentId]);
|
|
13676
|
-
}
|
|
13677
|
-
const messageId = `m-${createdAtMs.toString(36)}-${Math.random().toString(36).slice(2, 6)}`;
|
|
13678
|
-
const speechText = input.shouldSpeak ? input.body.trim() : "";
|
|
13679
|
-
const returnAddress = buildScoutReturnAddress2(broker.snapshot, senderId, {
|
|
13680
|
-
conversationId: conversation.id,
|
|
13681
|
-
replyToMessageId: messageId
|
|
13682
|
-
});
|
|
13683
14089
|
const workItem = input.workItem ? await createScoutTrackedWorkItem({
|
|
13684
14090
|
baseUrl: broker.baseUrl,
|
|
13685
14091
|
senderId,
|
|
13686
14092
|
targetAgentId,
|
|
13687
|
-
conversationId: conversation.id,
|
|
14093
|
+
conversationId: delivery.conversation.id,
|
|
13688
14094
|
createdAtMs,
|
|
13689
14095
|
source,
|
|
13690
14096
|
workItem: input.workItem
|
|
13691
14097
|
}) : undefined;
|
|
13692
|
-
await brokerPostJson(broker.baseUrl, scoutBrokerPaths.v1.messages, {
|
|
13693
|
-
id: messageId,
|
|
13694
|
-
conversationId: conversation.id,
|
|
13695
|
-
actorId: senderId,
|
|
13696
|
-
originNodeId: broker.node.id,
|
|
13697
|
-
class: conversation.kind === "system" ? "system" : "agent",
|
|
13698
|
-
body: input.body.trim(),
|
|
13699
|
-
mentions: [{ actorId: targetAgentId, label: targetLabel }],
|
|
13700
|
-
speech: speechText ? { text: speechText } : undefined,
|
|
13701
|
-
audience: {
|
|
13702
|
-
notify: [targetAgentId],
|
|
13703
|
-
reason: relayAudienceReason(conversation)
|
|
13704
|
-
},
|
|
13705
|
-
visibility: conversation.visibility,
|
|
13706
|
-
policy: "durable",
|
|
13707
|
-
createdAt: createdAtMs,
|
|
13708
|
-
metadata: {
|
|
13709
|
-
source,
|
|
13710
|
-
relayChannel: relayChannelMetadata(conversation, input.channel),
|
|
13711
|
-
relayTarget: targetAgentId,
|
|
13712
|
-
collaborationRecordId: workItem?.id,
|
|
13713
|
-
returnAddress
|
|
13714
|
-
}
|
|
13715
|
-
});
|
|
13716
|
-
const invocationResponse = await brokerPostJson(broker.baseUrl, scoutBrokerPaths.v1.invocations, {
|
|
13717
|
-
id: `inv-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`,
|
|
13718
|
-
requesterId: senderId,
|
|
13719
|
-
requesterNodeId: broker.node.id,
|
|
13720
|
-
targetAgentId,
|
|
13721
|
-
action: "consult",
|
|
13722
|
-
task: input.body.trim(),
|
|
13723
|
-
collaborationRecordId: workItem?.id,
|
|
13724
|
-
conversationId: conversation.id,
|
|
13725
|
-
messageId,
|
|
13726
|
-
execution: input.executionHarness ? { harness: input.executionHarness } : undefined,
|
|
13727
|
-
ensureAwake: true,
|
|
13728
|
-
stream: false,
|
|
13729
|
-
createdAt: createdAtMs,
|
|
13730
|
-
metadata: {
|
|
13731
|
-
source,
|
|
13732
|
-
relayChannel: relayChannelMetadata(conversation, input.channel),
|
|
13733
|
-
relayTarget: targetAgentId,
|
|
13734
|
-
collaborationRecordId: workItem?.id,
|
|
13735
|
-
returnAddress
|
|
13736
|
-
}
|
|
13737
|
-
});
|
|
13738
14098
|
return {
|
|
13739
14099
|
usedBroker: true,
|
|
13740
|
-
flight:
|
|
13741
|
-
conversationId: conversation.id,
|
|
13742
|
-
messageId,
|
|
14100
|
+
flight: delivery.flight,
|
|
14101
|
+
conversationId: delivery.conversation.id,
|
|
14102
|
+
messageId: delivery.message.id,
|
|
13743
14103
|
workItem
|
|
13744
14104
|
};
|
|
13745
14105
|
}
|
|
@@ -13750,104 +14110,49 @@ async function askScoutQuestion(input) {
|
|
|
13750
14110
|
}
|
|
13751
14111
|
const currentDirectory = input.currentDirectory ?? process.cwd();
|
|
13752
14112
|
const senderId = await resolveConversationActorId(broker.baseUrl, broker.snapshot, broker.node.id, input.senderId, currentDirectory);
|
|
13753
|
-
const
|
|
13754
|
-
|
|
13755
|
-
|
|
13756
|
-
|
|
13757
|
-
|
|
13758
|
-
|
|
13759
|
-
|
|
13760
|
-
|
|
13761
|
-
|
|
13762
|
-
|
|
13763
|
-
|
|
13764
|
-
|
|
13765
|
-
|
|
13766
|
-
|
|
13767
|
-
|
|
13768
|
-
|
|
13769
|
-
|
|
14113
|
+
const createdAt = input.createdAtMs ?? Date.now();
|
|
14114
|
+
const normalizedTargetLabel = renderScoutTargetLabel(input.targetLabel);
|
|
14115
|
+
const messageBody = input.body.trim().startsWith(normalizedTargetLabel) ? input.body.trim() : `${normalizedTargetLabel} ${input.body.trim()}`;
|
|
14116
|
+
const delivery = await brokerPostJson(broker.baseUrl, scoutBrokerPaths.v1.deliver, {
|
|
14117
|
+
id: `deliver-${createdAt.toString(36)}-${Math.random().toString(36).slice(2, 8)}`,
|
|
14118
|
+
requesterId: senderId,
|
|
14119
|
+
requesterNodeId: broker.node.id,
|
|
14120
|
+
targetLabel: input.targetLabel,
|
|
14121
|
+
body: messageBody,
|
|
14122
|
+
intent: "consult",
|
|
14123
|
+
channel: input.channel,
|
|
14124
|
+
speechText: input.shouldSpeak ? stripScoutAgentSelectorLabels(messageBody) : undefined,
|
|
14125
|
+
execution: input.executionHarness ? { harness: input.executionHarness } : undefined,
|
|
14126
|
+
ensureAwake: true,
|
|
14127
|
+
createdAt,
|
|
14128
|
+
messageMetadata: {
|
|
14129
|
+
source: "scout-cli"
|
|
14130
|
+
},
|
|
14131
|
+
invocationMetadata: {
|
|
14132
|
+
source: "scout-cli"
|
|
14133
|
+
}
|
|
14134
|
+
});
|
|
14135
|
+
if (delivery.kind !== "delivery") {
|
|
13770
14136
|
return {
|
|
13771
14137
|
usedBroker: true,
|
|
13772
14138
|
unresolvedTarget: input.targetLabel,
|
|
13773
|
-
targetDiagnostic:
|
|
14139
|
+
targetDiagnostic: scoutTargetDiagnosticFromDeliveryFailure(delivery)
|
|
13774
14140
|
};
|
|
13775
14141
|
}
|
|
13776
|
-
|
|
13777
|
-
if (!input.channel) {
|
|
13778
|
-
const dm = await ensureBrokerDirectConversationBetween(broker.baseUrl, broker.snapshot, broker.node.id, senderId, target.agentId);
|
|
13779
|
-
conversation = dm.conversation;
|
|
13780
|
-
} else {
|
|
13781
|
-
conversation = await ensureBrokerConversation(broker.baseUrl, broker.snapshot, broker.node.id, input.channel, senderId, [target.agentId]);
|
|
13782
|
-
}
|
|
13783
|
-
const messageId = `m-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;
|
|
13784
|
-
const messageBody = input.body.trim().startsWith(target.label) ? input.body.trim() : `${target.label} ${input.body.trim()}`;
|
|
13785
|
-
const speechText = input.shouldSpeak ? stripScoutAgentSelectorLabels(messageBody) : "";
|
|
13786
|
-
const createdAt = input.createdAtMs ?? Date.now();
|
|
13787
|
-
const returnAddress = buildScoutReturnAddress2(broker.snapshot, senderId, {
|
|
13788
|
-
conversationId: conversation.id,
|
|
13789
|
-
replyToMessageId: messageId
|
|
13790
|
-
});
|
|
13791
|
-
const workItem = input.workItem ? await createScoutTrackedWorkItem({
|
|
14142
|
+
const workItem = input.workItem && delivery.targetAgentId ? await createScoutTrackedWorkItem({
|
|
13792
14143
|
baseUrl: broker.baseUrl,
|
|
13793
14144
|
senderId,
|
|
13794
|
-
targetAgentId:
|
|
13795
|
-
conversationId: conversation.id,
|
|
14145
|
+
targetAgentId: delivery.targetAgentId,
|
|
14146
|
+
conversationId: delivery.conversation.id,
|
|
13796
14147
|
createdAtMs: createdAt,
|
|
13797
14148
|
source: "scout-cli",
|
|
13798
14149
|
workItem: input.workItem
|
|
13799
14150
|
}) : undefined;
|
|
13800
|
-
await brokerPostJson(broker.baseUrl, scoutBrokerPaths.v1.messages, {
|
|
13801
|
-
id: messageId,
|
|
13802
|
-
conversationId: conversation.id,
|
|
13803
|
-
actorId: senderId,
|
|
13804
|
-
originNodeId: broker.node.id,
|
|
13805
|
-
class: conversation.kind === "system" ? "system" : "agent",
|
|
13806
|
-
body: messageBody,
|
|
13807
|
-
mentions: [{ actorId: target.agentId, label: target.label }],
|
|
13808
|
-
speech: speechText ? { text: speechText } : undefined,
|
|
13809
|
-
audience: {
|
|
13810
|
-
notify: [target.agentId],
|
|
13811
|
-
reason: relayAudienceReason(conversation)
|
|
13812
|
-
},
|
|
13813
|
-
visibility: conversation.visibility,
|
|
13814
|
-
policy: "durable",
|
|
13815
|
-
createdAt,
|
|
13816
|
-
metadata: {
|
|
13817
|
-
source: "scout-cli",
|
|
13818
|
-
relayChannel: relayChannelMetadata(conversation, input.channel),
|
|
13819
|
-
relayTarget: target.agentId,
|
|
13820
|
-
collaborationRecordId: workItem?.id,
|
|
13821
|
-
returnAddress
|
|
13822
|
-
}
|
|
13823
|
-
});
|
|
13824
|
-
const invocationResponse = await brokerPostJson(broker.baseUrl, scoutBrokerPaths.v1.invocations, {
|
|
13825
|
-
id: `inv-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`,
|
|
13826
|
-
requesterId: senderId,
|
|
13827
|
-
requesterNodeId: broker.node.id,
|
|
13828
|
-
targetAgentId: target.agentId,
|
|
13829
|
-
action: "consult",
|
|
13830
|
-
task: messageBody,
|
|
13831
|
-
collaborationRecordId: workItem?.id,
|
|
13832
|
-
conversationId: conversation.id,
|
|
13833
|
-
messageId,
|
|
13834
|
-
execution: input.executionHarness ? { harness: input.executionHarness } : undefined,
|
|
13835
|
-
ensureAwake: true,
|
|
13836
|
-
stream: false,
|
|
13837
|
-
createdAt,
|
|
13838
|
-
metadata: {
|
|
13839
|
-
source: "scout-cli",
|
|
13840
|
-
relayChannel: relayChannelMetadata(conversation, input.channel),
|
|
13841
|
-
relayTarget: target.agentId,
|
|
13842
|
-
collaborationRecordId: workItem?.id,
|
|
13843
|
-
returnAddress
|
|
13844
|
-
}
|
|
13845
|
-
});
|
|
13846
14151
|
return {
|
|
13847
14152
|
usedBroker: true,
|
|
13848
|
-
flight:
|
|
13849
|
-
conversationId: conversation.id,
|
|
13850
|
-
messageId,
|
|
14153
|
+
flight: delivery.flight,
|
|
14154
|
+
conversationId: delivery.conversation.id,
|
|
14155
|
+
messageId: delivery.message.id,
|
|
13851
14156
|
workItem
|
|
13852
14157
|
};
|
|
13853
14158
|
}
|
|
@@ -13880,7 +14185,7 @@ async function waitForScoutFlight(baseUrl, flightId, options = {}) {
|
|
|
13880
14185
|
if (deadline !== null && Date.now() > deadline) {
|
|
13881
14186
|
throw new Error(`Timed out waiting for flight ${flight.id}.`);
|
|
13882
14187
|
}
|
|
13883
|
-
await new Promise((
|
|
14188
|
+
await new Promise((resolve10) => setTimeout(resolve10, 1000));
|
|
13884
14189
|
}
|
|
13885
14190
|
}
|
|
13886
14191
|
async function loadScoutMessages(options = {}) {
|
|
@@ -14085,7 +14390,7 @@ async function listScoutAgents(options = {}) {
|
|
|
14085
14390
|
}
|
|
14086
14391
|
async function loadScoutRelayConfig() {
|
|
14087
14392
|
try {
|
|
14088
|
-
const raw = await
|
|
14393
|
+
const raw = await readFile8(join14(relayHubDirectory(), "config.json"), "utf8");
|
|
14089
14394
|
return JSON.parse(raw);
|
|
14090
14395
|
} catch {
|
|
14091
14396
|
return {};
|
|
@@ -14107,15 +14412,15 @@ function applyPronunciations(text, pronunciations) {
|
|
|
14107
14412
|
async function acquireScoutOnAir(agent, timeoutMs = 30000) {
|
|
14108
14413
|
const hub = relayHubDirectory();
|
|
14109
14414
|
await mkdir7(hub, { recursive: true });
|
|
14110
|
-
const lockPath =
|
|
14415
|
+
const lockPath = join14(hub, "on-air.lock");
|
|
14111
14416
|
const deadline = Date.now() + timeoutMs;
|
|
14112
14417
|
while (Date.now() < deadline) {
|
|
14113
14418
|
try {
|
|
14114
|
-
const raw = await
|
|
14419
|
+
const raw = await readFile8(lockPath, "utf8");
|
|
14115
14420
|
const lock = JSON.parse(raw);
|
|
14116
14421
|
if (Date.now() - Number(lock.ts ?? 0) > 30000)
|
|
14117
14422
|
break;
|
|
14118
|
-
await new Promise((
|
|
14423
|
+
await new Promise((resolve10) => setTimeout(resolve10, 2000));
|
|
14119
14424
|
} catch {
|
|
14120
14425
|
break;
|
|
14121
14426
|
}
|
|
@@ -14125,7 +14430,7 @@ async function acquireScoutOnAir(agent, timeoutMs = 30000) {
|
|
|
14125
14430
|
}
|
|
14126
14431
|
async function releaseScoutOnAir() {
|
|
14127
14432
|
try {
|
|
14128
|
-
await unlink(
|
|
14433
|
+
await unlink(join14(relayHubDirectory(), "on-air.lock"));
|
|
14129
14434
|
} catch {}
|
|
14130
14435
|
}
|
|
14131
14436
|
async function speakScoutText(text, voice) {
|
|
@@ -14172,10 +14477,10 @@ async function speakScoutText(text, voice) {
|
|
|
14172
14477
|
player.stdin.write(value);
|
|
14173
14478
|
}
|
|
14174
14479
|
player.stdin.end();
|
|
14175
|
-
await new Promise((
|
|
14480
|
+
await new Promise((resolve10) => player.on("close", () => resolve10()));
|
|
14176
14481
|
}
|
|
14177
14482
|
function buildScoutEnrollmentPrompt(input) {
|
|
14178
|
-
const relayLogPath =
|
|
14483
|
+
const relayLogPath = join14(relayHubDirectory(), "channel.log");
|
|
14179
14484
|
const cliCommand = input.cliCommand?.trim() || "scout";
|
|
14180
14485
|
const task = input.task?.trim();
|
|
14181
14486
|
return [
|
|
@@ -14219,7 +14524,7 @@ __export(exports_ask, {
|
|
|
14219
14524
|
});
|
|
14220
14525
|
function renderAskCommandHelp() {
|
|
14221
14526
|
return [
|
|
14222
|
-
"Usage: scout ask --to <agent> [--as <sender>] [--channel <name>] [--timeout <seconds>] [--harness <runtime>] <message>",
|
|
14527
|
+
"Usage: scout ask --to <agent> [--as <sender>] [--channel <name>] [--timeout <seconds>] [--harness <runtime>] [--prompt-file <path> | <message>]",
|
|
14223
14528
|
"",
|
|
14224
14529
|
"Ask one agent to do work or return a concrete answer.",
|
|
14225
14530
|
"",
|
|
@@ -14231,14 +14536,20 @@ function renderAskCommandHelp() {
|
|
|
14231
14536
|
'Use ask when the meaning is "do this and get back to me."',
|
|
14232
14537
|
"Keep progress, review, and completion in that same DM or explicit channel.",
|
|
14233
14538
|
"",
|
|
14539
|
+
"Input:",
|
|
14540
|
+
" inline message -> primary prompt body",
|
|
14541
|
+
" --prompt-file <path> -> read the primary prompt body from a UTF-8 file",
|
|
14542
|
+
" --body-file <path> -> alias for --prompt-file",
|
|
14543
|
+
"",
|
|
14234
14544
|
"Examples:",
|
|
14235
14545
|
' scout ask --to hudson "review the parser"',
|
|
14546
|
+
" scout ask --to hudson --prompt-file ./handoff.md",
|
|
14236
14547
|
' scout ask --as premotion.master.mini --to hudson "build the editor"',
|
|
14237
14548
|
' scout ask --to vox.harness:codex "take another pass on the runtime fix"'
|
|
14238
14549
|
].join(`
|
|
14239
14550
|
`);
|
|
14240
14551
|
}
|
|
14241
|
-
function
|
|
14552
|
+
function renderScoutTargetLabel2(targetLabel) {
|
|
14242
14553
|
const trimmed = targetLabel.trim();
|
|
14243
14554
|
return trimmed.startsWith("@") ? trimmed : `@${trimmed}`;
|
|
14244
14555
|
}
|
|
@@ -14258,7 +14569,7 @@ function renderConversationRoute(conversationId) {
|
|
|
14258
14569
|
return conversationId.startsWith("dm.") ? `DM ${conversationId}` : `conversation ${conversationId}`;
|
|
14259
14570
|
}
|
|
14260
14571
|
function formatScoutAskRoutingError(result, targetLabel) {
|
|
14261
|
-
const renderedTarget =
|
|
14572
|
+
const renderedTarget = renderScoutTargetLabel2(targetLabel);
|
|
14262
14573
|
const diagnostic = result.targetDiagnostic;
|
|
14263
14574
|
if (diagnostic?.state === "ambiguous") {
|
|
14264
14575
|
const rendered = diagnostic.candidates.map((candidate) => renderAmbiguousCandidate(candidate.label || candidate.agentId)).filter((label) => label.length > 0);
|
|
@@ -14279,6 +14590,17 @@ function formatScoutAskRoutingError(result, targetLabel) {
|
|
|
14279
14590
|
}
|
|
14280
14591
|
return `target ${renderedTarget} is offline; nothing was sent. Run \`scout who\` to inspect the target before retrying.`;
|
|
14281
14592
|
}
|
|
14593
|
+
if (diagnostic?.state === "unavailable") {
|
|
14594
|
+
const runtime = diagnostic.transport ? ` (${diagnostic.transport})` : "";
|
|
14595
|
+
const wakePolicy = diagnostic.wakePolicy ? ` [wake:${diagnostic.wakePolicy}]` : "";
|
|
14596
|
+
return `target ${renderedTarget} is known but currently unavailable${runtime}${wakePolicy}; nothing was sent. ${diagnostic.detail}`;
|
|
14597
|
+
}
|
|
14598
|
+
if (diagnostic?.state === "unknown") {
|
|
14599
|
+
return `there is no ${renderedTarget}; nothing was sent.`;
|
|
14600
|
+
}
|
|
14601
|
+
if (diagnostic?.state === "invalid" || diagnostic?.state === "missing") {
|
|
14602
|
+
return `${diagnostic.detail}; nothing was sent.`;
|
|
14603
|
+
}
|
|
14282
14604
|
return `target ${renderedTarget} is not currently routable; nothing was sent.`;
|
|
14283
14605
|
}
|
|
14284
14606
|
async function runAskCommand(context, args) {
|
|
@@ -14292,10 +14614,11 @@ async function runAskCommand(context, args) {
|
|
|
14292
14614
|
async function runAskWithOptions(context, options) {
|
|
14293
14615
|
const currentDirectory = options.currentDirectory ?? defaultScoutContextDirectory(context);
|
|
14294
14616
|
const senderId = await resolveScoutSenderId(options.agentName, currentDirectory, context.env);
|
|
14617
|
+
const body = await resolvePromptBody(options);
|
|
14295
14618
|
const result = await askScoutQuestion({
|
|
14296
14619
|
senderId,
|
|
14297
14620
|
targetLabel: options.targetLabel,
|
|
14298
|
-
body
|
|
14621
|
+
body,
|
|
14299
14622
|
channel: options.channel,
|
|
14300
14623
|
executionHarness: parseScoutHarness(options.harness),
|
|
14301
14624
|
currentDirectory
|
|
@@ -14323,6 +14646,7 @@ var HELP_FLAGS;
|
|
|
14323
14646
|
var init_ask = __esm(async () => {
|
|
14324
14647
|
init_context();
|
|
14325
14648
|
init_options();
|
|
14649
|
+
init_input_file();
|
|
14326
14650
|
await init_service();
|
|
14327
14651
|
HELP_FLAGS = new Set(["--help", "-h"]);
|
|
14328
14652
|
});
|
|
@@ -14474,7 +14798,7 @@ __export(exports_send, {
|
|
|
14474
14798
|
});
|
|
14475
14799
|
function renderSendCommandHelp() {
|
|
14476
14800
|
return [
|
|
14477
|
-
"Usage: scout send [--as <sender>] [--channel <name>] [--speak] [--harness <runtime>] <message>",
|
|
14801
|
+
"Usage: scout send [--as <sender>] [--channel <name>] [--speak] [--harness <runtime>] [--message-file <path> | <message>]",
|
|
14478
14802
|
"",
|
|
14479
14803
|
"Tell or update another agent or an explicit channel.",
|
|
14480
14804
|
"",
|
|
@@ -14487,8 +14811,14 @@ function renderSendCommandHelp() {
|
|
|
14487
14811
|
"Use send for heads-up, replies, and status updates.",
|
|
14488
14812
|
'Use `scout ask` when the meaning is "do this and get back to me."',
|
|
14489
14813
|
"",
|
|
14814
|
+
"Input:",
|
|
14815
|
+
" inline message -> message body",
|
|
14816
|
+
" --message-file <path> -> read the message body from a UTF-8 file",
|
|
14817
|
+
" --body-file <path> -> alias for --message-file",
|
|
14818
|
+
"",
|
|
14490
14819
|
"Examples:",
|
|
14491
14820
|
' scout send "@hudson ready for review"',
|
|
14821
|
+
" scout send --channel triage --message-file ./status.md",
|
|
14492
14822
|
' scout send --as premotion.master.mini "@hudson editor branch is green"',
|
|
14493
14823
|
' scout send --channel triage "need two reviewers"'
|
|
14494
14824
|
].join(`
|
|
@@ -14501,8 +14831,31 @@ function renderTargetLabel(label) {
|
|
|
14501
14831
|
}
|
|
14502
14832
|
return trimmed.startsWith("@") ? trimmed : `@${trimmed}`;
|
|
14503
14833
|
}
|
|
14504
|
-
function
|
|
14505
|
-
const rendered =
|
|
14834
|
+
function renderAmbiguousCandidate2(label) {
|
|
14835
|
+
const rendered = renderTargetLabel(label);
|
|
14836
|
+
return rendered || label.trim();
|
|
14837
|
+
}
|
|
14838
|
+
function formatScoutSendRoutingError(result) {
|
|
14839
|
+
const diagnostic = result.targetDiagnostic;
|
|
14840
|
+
if (diagnostic?.state === "unknown") {
|
|
14841
|
+
return `there is no ${renderTargetLabel(diagnostic.agentId)}; nothing was sent.`;
|
|
14842
|
+
}
|
|
14843
|
+
if (diagnostic?.state === "ambiguous") {
|
|
14844
|
+
const renderedCandidates = diagnostic.candidates.map((candidate) => renderAmbiguousCandidate2(candidate.label || candidate.agentId)).filter((label) => label.length > 0);
|
|
14845
|
+
if (renderedCandidates.length > 0) {
|
|
14846
|
+
return `target ${renderTargetLabel(result.unresolvedTargets[0] ?? "")} matches multiple agents: ${renderedCandidates.join(", ")}. Re-run with the fully qualified form (e.g. \`scout send "${renderedCandidates[0]} ..."\`).`;
|
|
14847
|
+
}
|
|
14848
|
+
return `target ${renderTargetLabel(result.unresolvedTargets[0] ?? "")} matches multiple agents; nothing was sent. Re-run with a fully qualified @handle to disambiguate.`;
|
|
14849
|
+
}
|
|
14850
|
+
if (diagnostic?.state === "unavailable") {
|
|
14851
|
+
const runtime = diagnostic.transport ? ` (${diagnostic.transport})` : "";
|
|
14852
|
+
const wakePolicy = diagnostic.wakePolicy ? ` [wake:${diagnostic.wakePolicy}]` : "";
|
|
14853
|
+
return `target ${renderTargetLabel(result.unresolvedTargets[0] ?? diagnostic.agentId)} is known but currently unavailable${runtime}${wakePolicy}; nothing was sent. ${diagnostic.detail}`;
|
|
14854
|
+
}
|
|
14855
|
+
if (diagnostic?.state === "invalid" || diagnostic?.state === "missing") {
|
|
14856
|
+
return `${diagnostic.detail}; nothing was sent.`;
|
|
14857
|
+
}
|
|
14858
|
+
const rendered = result.unresolvedTargets.map(renderTargetLabel).filter((label) => label.length > 0);
|
|
14506
14859
|
if (rendered.length === 1) {
|
|
14507
14860
|
return `target ${rendered[0]} is not uniquely routable; nothing was sent.`;
|
|
14508
14861
|
}
|
|
@@ -14522,9 +14875,10 @@ async function runSendCommand(context, args) {
|
|
|
14522
14875
|
const options = parseSendCommandOptions(args, defaultScoutContextDirectory(context));
|
|
14523
14876
|
const currentDirectory = options.currentDirectory ?? defaultScoutContextDirectory(context);
|
|
14524
14877
|
const senderId = await resolveScoutSenderId(options.agentName, currentDirectory, context.env);
|
|
14878
|
+
const body = await resolveMessageBody(options);
|
|
14525
14879
|
const result = await sendScoutMessage({
|
|
14526
14880
|
senderId,
|
|
14527
|
-
body
|
|
14881
|
+
body,
|
|
14528
14882
|
channel: options.channel,
|
|
14529
14883
|
shouldSpeak: options.shouldSpeak,
|
|
14530
14884
|
executionHarness: parseScoutHarness(options.harness),
|
|
@@ -14534,7 +14888,7 @@ async function runSendCommand(context, args) {
|
|
|
14534
14888
|
throw new Error("broker is not reachable");
|
|
14535
14889
|
}
|
|
14536
14890
|
if (result.unresolvedTargets.length > 0) {
|
|
14537
|
-
throw new Error(formatScoutSendRoutingError(result
|
|
14891
|
+
throw new Error(formatScoutSendRoutingError(result));
|
|
14538
14892
|
}
|
|
14539
14893
|
if (result.routingError) {
|
|
14540
14894
|
throw new Error(formatScoutRouteChoiceError(result.routingError));
|
|
@@ -14542,7 +14896,7 @@ async function runSendCommand(context, args) {
|
|
|
14542
14896
|
context.output.writeValue({
|
|
14543
14897
|
senderId,
|
|
14544
14898
|
conversationId: result.conversationId,
|
|
14545
|
-
message:
|
|
14899
|
+
message: body,
|
|
14546
14900
|
invokedTargets: result.invokedTargets,
|
|
14547
14901
|
unresolvedTargets: result.unresolvedTargets,
|
|
14548
14902
|
routeKind: result.routeKind
|
|
@@ -14551,6 +14905,7 @@ async function runSendCommand(context, args) {
|
|
|
14551
14905
|
var HELP_FLAGS2;
|
|
14552
14906
|
var init_send = __esm(async () => {
|
|
14553
14907
|
init_context();
|
|
14908
|
+
init_input_file();
|
|
14554
14909
|
init_options();
|
|
14555
14910
|
init_broker();
|
|
14556
14911
|
await init_service();
|
|
@@ -14565,15 +14920,21 @@ __export(exports_broadcast, {
|
|
|
14565
14920
|
});
|
|
14566
14921
|
function renderBroadcastCommandHelp() {
|
|
14567
14922
|
return [
|
|
14568
|
-
"Usage: scout broadcast [--as <sender>] [--harness <runtime>] <message>",
|
|
14923
|
+
"Usage: scout broadcast [--as <sender>] [--harness <runtime>] [--message-file <path> | <message>]",
|
|
14569
14924
|
"",
|
|
14570
14925
|
"Broadcast to channel.shared.",
|
|
14571
14926
|
"",
|
|
14572
14927
|
"Use this only when the message is genuinely for everyone.",
|
|
14573
14928
|
"Do not use broadcast for ordinary one-to-one delegation or small-group coordination.",
|
|
14574
14929
|
"",
|
|
14930
|
+
"Input:",
|
|
14931
|
+
" inline message -> broadcast body",
|
|
14932
|
+
" --message-file <path> -> read the broadcast body from a UTF-8 file",
|
|
14933
|
+
" --body-file <path> -> alias for --message-file",
|
|
14934
|
+
"",
|
|
14575
14935
|
"Examples:",
|
|
14576
14936
|
' scout broadcast "deploying in 15m, pause long flights"',
|
|
14937
|
+
" scout broadcast --message-file ./maintenance.md",
|
|
14577
14938
|
' scout broadcast --as scout.main.mini "broker maintenance starts now"'
|
|
14578
14939
|
].join(`
|
|
14579
14940
|
`);
|
|
@@ -14589,9 +14950,10 @@ async function runBroadcastCommand(context, args) {
|
|
|
14589
14950
|
}
|
|
14590
14951
|
const currentDirectory = options.currentDirectory ?? defaultScoutContextDirectory(context);
|
|
14591
14952
|
const senderId = await resolveScoutSenderId(options.agentName, currentDirectory, context.env);
|
|
14953
|
+
const body = await resolveMessageBody(options);
|
|
14592
14954
|
const result = await sendScoutMessage({
|
|
14593
14955
|
senderId,
|
|
14594
|
-
body: `@all ${
|
|
14956
|
+
body: `@all ${body}`,
|
|
14595
14957
|
channel: "shared",
|
|
14596
14958
|
executionHarness: parseScoutHarness(options.harness),
|
|
14597
14959
|
currentDirectory
|
|
@@ -14600,10 +14962,10 @@ async function runBroadcastCommand(context, args) {
|
|
|
14600
14962
|
throw new Error("broker is not reachable");
|
|
14601
14963
|
}
|
|
14602
14964
|
if (result.unresolvedTargets.length > 0) {
|
|
14603
|
-
throw new Error(formatScoutSendRoutingError(result
|
|
14965
|
+
throw new Error(formatScoutSendRoutingError(result));
|
|
14604
14966
|
}
|
|
14605
14967
|
context.output.writeValue({
|
|
14606
|
-
message:
|
|
14968
|
+
message: body,
|
|
14607
14969
|
invokedTargets: result.invokedTargets,
|
|
14608
14970
|
unresolvedTargets: result.unresolvedTargets,
|
|
14609
14971
|
routeKind: result.routeKind
|
|
@@ -14613,6 +14975,7 @@ var HELP_FLAGS3;
|
|
|
14613
14975
|
var init_broadcast = __esm(async () => {
|
|
14614
14976
|
init_context();
|
|
14615
14977
|
init_errors();
|
|
14978
|
+
init_input_file();
|
|
14616
14979
|
init_options();
|
|
14617
14980
|
init_broker();
|
|
14618
14981
|
await __promiseAll([
|
|
@@ -14759,7 +15122,8 @@ async function createScoutAgentCard(input) {
|
|
|
14759
15122
|
displayName: input.displayName,
|
|
14760
15123
|
harness: input.harness,
|
|
14761
15124
|
model: input.model,
|
|
14762
|
-
currentDirectory: input.currentDirectory
|
|
15125
|
+
currentDirectory: input.currentDirectory,
|
|
15126
|
+
ensureOnline: false
|
|
14763
15127
|
});
|
|
14764
15128
|
const currentDirectory = input.currentDirectory ?? input.projectPath;
|
|
14765
15129
|
const broker = await loadScoutBrokerContext();
|
|
@@ -14857,11 +15221,11 @@ function renderCardCommandHelp() {
|
|
|
14857
15221
|
`);
|
|
14858
15222
|
}
|
|
14859
15223
|
function promptWithDefault(question, defaultValue) {
|
|
14860
|
-
return new Promise((
|
|
15224
|
+
return new Promise((resolve10) => {
|
|
14861
15225
|
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
14862
15226
|
rl.question(` ${question} [${defaultValue}]: `, (answer) => {
|
|
14863
15227
|
rl.close();
|
|
14864
|
-
|
|
15228
|
+
resolve10(answer.trim() || defaultValue);
|
|
14865
15229
|
});
|
|
14866
15230
|
});
|
|
14867
15231
|
}
|
|
@@ -35590,7 +35954,7 @@ class Protocol {
|
|
|
35590
35954
|
return;
|
|
35591
35955
|
}
|
|
35592
35956
|
const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1000;
|
|
35593
|
-
await new Promise((
|
|
35957
|
+
await new Promise((resolve10) => setTimeout(resolve10, pollInterval));
|
|
35594
35958
|
options?.signal?.throwIfAborted();
|
|
35595
35959
|
}
|
|
35596
35960
|
} catch (error48) {
|
|
@@ -35602,7 +35966,7 @@ class Protocol {
|
|
|
35602
35966
|
}
|
|
35603
35967
|
request(request, resultSchema, options) {
|
|
35604
35968
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
35605
|
-
return new Promise((
|
|
35969
|
+
return new Promise((resolve10, reject) => {
|
|
35606
35970
|
const earlyReject = (error48) => {
|
|
35607
35971
|
reject(error48);
|
|
35608
35972
|
};
|
|
@@ -35680,7 +36044,7 @@ class Protocol {
|
|
|
35680
36044
|
if (!parseResult.success) {
|
|
35681
36045
|
reject(parseResult.error);
|
|
35682
36046
|
} else {
|
|
35683
|
-
|
|
36047
|
+
resolve10(parseResult.data);
|
|
35684
36048
|
}
|
|
35685
36049
|
} catch (error48) {
|
|
35686
36050
|
reject(error48);
|
|
@@ -35871,12 +36235,12 @@ class Protocol {
|
|
|
35871
36235
|
interval = task.pollInterval;
|
|
35872
36236
|
}
|
|
35873
36237
|
} catch {}
|
|
35874
|
-
return new Promise((
|
|
36238
|
+
return new Promise((resolve10, reject) => {
|
|
35875
36239
|
if (signal.aborted) {
|
|
35876
36240
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
35877
36241
|
return;
|
|
35878
36242
|
}
|
|
35879
|
-
const timeoutId = setTimeout(
|
|
36243
|
+
const timeoutId = setTimeout(resolve10, interval);
|
|
35880
36244
|
signal.addEventListener("abort", () => {
|
|
35881
36245
|
clearTimeout(timeoutId);
|
|
35882
36246
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
@@ -36353,11 +36717,11 @@ var require_codegen = __commonJS((exports) => {
|
|
|
36353
36717
|
const rhs = this.rhs === undefined ? "" : ` = ${this.rhs}`;
|
|
36354
36718
|
return `${varKind} ${this.name}${rhs};` + _n;
|
|
36355
36719
|
}
|
|
36356
|
-
optimizeNames(names,
|
|
36720
|
+
optimizeNames(names, constants5) {
|
|
36357
36721
|
if (!names[this.name.str])
|
|
36358
36722
|
return;
|
|
36359
36723
|
if (this.rhs)
|
|
36360
|
-
this.rhs = optimizeExpr(this.rhs, names,
|
|
36724
|
+
this.rhs = optimizeExpr(this.rhs, names, constants5);
|
|
36361
36725
|
return this;
|
|
36362
36726
|
}
|
|
36363
36727
|
get names() {
|
|
@@ -36375,10 +36739,10 @@ var require_codegen = __commonJS((exports) => {
|
|
|
36375
36739
|
render({ _n }) {
|
|
36376
36740
|
return `${this.lhs} = ${this.rhs};` + _n;
|
|
36377
36741
|
}
|
|
36378
|
-
optimizeNames(names,
|
|
36742
|
+
optimizeNames(names, constants5) {
|
|
36379
36743
|
if (this.lhs instanceof code_1.Name && !names[this.lhs.str] && !this.sideEffects)
|
|
36380
36744
|
return;
|
|
36381
|
-
this.rhs = optimizeExpr(this.rhs, names,
|
|
36745
|
+
this.rhs = optimizeExpr(this.rhs, names, constants5);
|
|
36382
36746
|
return this;
|
|
36383
36747
|
}
|
|
36384
36748
|
get names() {
|
|
@@ -36444,8 +36808,8 @@ var require_codegen = __commonJS((exports) => {
|
|
|
36444
36808
|
optimizeNodes() {
|
|
36445
36809
|
return `${this.code}` ? this : undefined;
|
|
36446
36810
|
}
|
|
36447
|
-
optimizeNames(names,
|
|
36448
|
-
this.code = optimizeExpr(this.code, names,
|
|
36811
|
+
optimizeNames(names, constants5) {
|
|
36812
|
+
this.code = optimizeExpr(this.code, names, constants5);
|
|
36449
36813
|
return this;
|
|
36450
36814
|
}
|
|
36451
36815
|
get names() {
|
|
@@ -36475,12 +36839,12 @@ var require_codegen = __commonJS((exports) => {
|
|
|
36475
36839
|
}
|
|
36476
36840
|
return nodes.length > 0 ? this : undefined;
|
|
36477
36841
|
}
|
|
36478
|
-
optimizeNames(names,
|
|
36842
|
+
optimizeNames(names, constants5) {
|
|
36479
36843
|
const { nodes } = this;
|
|
36480
36844
|
let i = nodes.length;
|
|
36481
36845
|
while (i--) {
|
|
36482
36846
|
const n = nodes[i];
|
|
36483
|
-
if (n.optimizeNames(names,
|
|
36847
|
+
if (n.optimizeNames(names, constants5))
|
|
36484
36848
|
continue;
|
|
36485
36849
|
subtractNames(names, n.names);
|
|
36486
36850
|
nodes.splice(i, 1);
|
|
@@ -36537,12 +36901,12 @@ var require_codegen = __commonJS((exports) => {
|
|
|
36537
36901
|
return;
|
|
36538
36902
|
return this;
|
|
36539
36903
|
}
|
|
36540
|
-
optimizeNames(names,
|
|
36904
|
+
optimizeNames(names, constants5) {
|
|
36541
36905
|
var _a2;
|
|
36542
|
-
this.else = (_a2 = this.else) === null || _a2 === undefined ? undefined : _a2.optimizeNames(names,
|
|
36543
|
-
if (!(super.optimizeNames(names,
|
|
36906
|
+
this.else = (_a2 = this.else) === null || _a2 === undefined ? undefined : _a2.optimizeNames(names, constants5);
|
|
36907
|
+
if (!(super.optimizeNames(names, constants5) || this.else))
|
|
36544
36908
|
return;
|
|
36545
|
-
this.condition = optimizeExpr(this.condition, names,
|
|
36909
|
+
this.condition = optimizeExpr(this.condition, names, constants5);
|
|
36546
36910
|
return this;
|
|
36547
36911
|
}
|
|
36548
36912
|
get names() {
|
|
@@ -36567,10 +36931,10 @@ var require_codegen = __commonJS((exports) => {
|
|
|
36567
36931
|
render(opts) {
|
|
36568
36932
|
return `for(${this.iteration})` + super.render(opts);
|
|
36569
36933
|
}
|
|
36570
|
-
optimizeNames(names,
|
|
36571
|
-
if (!super.optimizeNames(names,
|
|
36934
|
+
optimizeNames(names, constants5) {
|
|
36935
|
+
if (!super.optimizeNames(names, constants5))
|
|
36572
36936
|
return;
|
|
36573
|
-
this.iteration = optimizeExpr(this.iteration, names,
|
|
36937
|
+
this.iteration = optimizeExpr(this.iteration, names, constants5);
|
|
36574
36938
|
return this;
|
|
36575
36939
|
}
|
|
36576
36940
|
get names() {
|
|
@@ -36608,10 +36972,10 @@ var require_codegen = __commonJS((exports) => {
|
|
|
36608
36972
|
render(opts) {
|
|
36609
36973
|
return `for(${this.varKind} ${this.name} ${this.loop} ${this.iterable})` + super.render(opts);
|
|
36610
36974
|
}
|
|
36611
|
-
optimizeNames(names,
|
|
36612
|
-
if (!super.optimizeNames(names,
|
|
36975
|
+
optimizeNames(names, constants5) {
|
|
36976
|
+
if (!super.optimizeNames(names, constants5))
|
|
36613
36977
|
return;
|
|
36614
|
-
this.iterable = optimizeExpr(this.iterable, names,
|
|
36978
|
+
this.iterable = optimizeExpr(this.iterable, names, constants5);
|
|
36615
36979
|
return this;
|
|
36616
36980
|
}
|
|
36617
36981
|
get names() {
|
|
@@ -36656,11 +37020,11 @@ var require_codegen = __commonJS((exports) => {
|
|
|
36656
37020
|
(_b = this.finally) === null || _b === undefined || _b.optimizeNodes();
|
|
36657
37021
|
return this;
|
|
36658
37022
|
}
|
|
36659
|
-
optimizeNames(names,
|
|
37023
|
+
optimizeNames(names, constants5) {
|
|
36660
37024
|
var _a2, _b;
|
|
36661
|
-
super.optimizeNames(names,
|
|
36662
|
-
(_a2 = this.catch) === null || _a2 === undefined || _a2.optimizeNames(names,
|
|
36663
|
-
(_b = this.finally) === null || _b === undefined || _b.optimizeNames(names,
|
|
37025
|
+
super.optimizeNames(names, constants5);
|
|
37026
|
+
(_a2 = this.catch) === null || _a2 === undefined || _a2.optimizeNames(names, constants5);
|
|
37027
|
+
(_b = this.finally) === null || _b === undefined || _b.optimizeNames(names, constants5);
|
|
36664
37028
|
return this;
|
|
36665
37029
|
}
|
|
36666
37030
|
get names() {
|
|
@@ -36934,7 +37298,7 @@ var require_codegen = __commonJS((exports) => {
|
|
|
36934
37298
|
function addExprNames(names, from) {
|
|
36935
37299
|
return from instanceof code_1._CodeOrName ? addNames(names, from.names) : names;
|
|
36936
37300
|
}
|
|
36937
|
-
function optimizeExpr(expr, names,
|
|
37301
|
+
function optimizeExpr(expr, names, constants5) {
|
|
36938
37302
|
if (expr instanceof code_1.Name)
|
|
36939
37303
|
return replaceName(expr);
|
|
36940
37304
|
if (!canOptimize(expr))
|
|
@@ -36949,14 +37313,14 @@ var require_codegen = __commonJS((exports) => {
|
|
|
36949
37313
|
return items;
|
|
36950
37314
|
}, []));
|
|
36951
37315
|
function replaceName(n) {
|
|
36952
|
-
const c =
|
|
37316
|
+
const c = constants5[n.str];
|
|
36953
37317
|
if (c === undefined || names[n.str] !== 1)
|
|
36954
37318
|
return n;
|
|
36955
37319
|
delete names[n.str];
|
|
36956
37320
|
return c;
|
|
36957
37321
|
}
|
|
36958
37322
|
function canOptimize(e) {
|
|
36959
|
-
return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 &&
|
|
37323
|
+
return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 && constants5[c.str] !== undefined);
|
|
36960
37324
|
}
|
|
36961
37325
|
}
|
|
36962
37326
|
function subtractNames(names, from) {
|
|
@@ -38861,7 +39225,7 @@ var require_compile = __commonJS((exports) => {
|
|
|
38861
39225
|
const schOrFunc = root.refs[ref];
|
|
38862
39226
|
if (schOrFunc)
|
|
38863
39227
|
return schOrFunc;
|
|
38864
|
-
let _sch =
|
|
39228
|
+
let _sch = resolve10.call(this, root, ref);
|
|
38865
39229
|
if (_sch === undefined) {
|
|
38866
39230
|
const schema = (_a2 = root.localRefs) === null || _a2 === undefined ? undefined : _a2[ref];
|
|
38867
39231
|
const { schemaId } = this.opts;
|
|
@@ -38888,7 +39252,7 @@ var require_compile = __commonJS((exports) => {
|
|
|
38888
39252
|
function sameSchemaEnv(s1, s2) {
|
|
38889
39253
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
38890
39254
|
}
|
|
38891
|
-
function
|
|
39255
|
+
function resolve10(root, ref) {
|
|
38892
39256
|
let sch;
|
|
38893
39257
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
38894
39258
|
ref = sch;
|
|
@@ -39418,7 +39782,7 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
39418
39782
|
}
|
|
39419
39783
|
return uri;
|
|
39420
39784
|
}
|
|
39421
|
-
function
|
|
39785
|
+
function resolve10(baseURI, relativeURI, options) {
|
|
39422
39786
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
39423
39787
|
const resolved = resolveComponent(parse7(baseURI, schemelessOptions), parse7(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
39424
39788
|
schemelessOptions.skipEscape = true;
|
|
@@ -39646,7 +40010,7 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
39646
40010
|
var fastUri = {
|
|
39647
40011
|
SCHEMES,
|
|
39648
40012
|
normalize,
|
|
39649
|
-
resolve:
|
|
40013
|
+
resolve: resolve10,
|
|
39650
40014
|
resolveComponent,
|
|
39651
40015
|
equal,
|
|
39652
40016
|
serialize,
|
|
@@ -43029,12 +43393,12 @@ class StdioServerTransport {
|
|
|
43029
43393
|
this.onclose?.();
|
|
43030
43394
|
}
|
|
43031
43395
|
send(message) {
|
|
43032
|
-
return new Promise((
|
|
43396
|
+
return new Promise((resolve10) => {
|
|
43033
43397
|
const json2 = serializeMessage(message);
|
|
43034
43398
|
if (this._stdout.write(json2)) {
|
|
43035
|
-
|
|
43399
|
+
resolve10();
|
|
43036
43400
|
} else {
|
|
43037
|
-
this._stdout.once("drain",
|
|
43401
|
+
this._stdout.once("drain", resolve10);
|
|
43038
43402
|
}
|
|
43039
43403
|
});
|
|
43040
43404
|
}
|
|
@@ -43050,7 +43414,7 @@ var init_product = __esm(() => {
|
|
|
43050
43414
|
});
|
|
43051
43415
|
|
|
43052
43416
|
// ../../apps/desktop/src/core/mcp/scout-channel.ts
|
|
43053
|
-
import { resolve as
|
|
43417
|
+
import { resolve as resolve10 } from "path";
|
|
43054
43418
|
async function resolveAgentId(currentDirectory, env) {
|
|
43055
43419
|
return resolveScoutSenderId(undefined, currentDirectory, env);
|
|
43056
43420
|
}
|
|
@@ -43123,7 +43487,7 @@ function startBrokerSubscription(broker, agentId, onMessage, signal) {
|
|
|
43123
43487
|
}
|
|
43124
43488
|
async function runScoutChannelServer(options) {
|
|
43125
43489
|
const env = options.env ?? process.env;
|
|
43126
|
-
const currentDirectory =
|
|
43490
|
+
const currentDirectory = resolve10(options.defaultCurrentDirectory || process.cwd());
|
|
43127
43491
|
const agentId = await resolveAgentId(currentDirectory, env);
|
|
43128
43492
|
const brokerUrl = env.OPENSCOUT_BROKER_URL?.trim() || resolveScoutBrokerUrl();
|
|
43129
43493
|
const broker = await loadScoutBrokerContext(brokerUrl);
|
|
@@ -43435,8 +43799,11 @@ async function runDownCommand(context, args) {
|
|
|
43435
43799
|
let agent = await downScoutAgent(target);
|
|
43436
43800
|
if (!agent) {
|
|
43437
43801
|
const resolved = await resolveLocalAgentByName(target);
|
|
43438
|
-
|
|
43439
|
-
|
|
43802
|
+
const projectMatch = resolved ?? await resolveLocalAgentByName(target, {
|
|
43803
|
+
matchProjectName: true
|
|
43804
|
+
});
|
|
43805
|
+
if (projectMatch) {
|
|
43806
|
+
agent = await downScoutAgent(projectMatch.agentId);
|
|
43440
43807
|
}
|
|
43441
43808
|
}
|
|
43442
43809
|
context.output.writeValue(agent, renderScoutDownResult);
|
|
@@ -43452,110 +43819,43 @@ var init_down = __esm(async () => {
|
|
|
43452
43819
|
|
|
43453
43820
|
// ../../apps/desktop/src/app/host/runtime-service-client.ts
|
|
43454
43821
|
import { spawn as spawn4 } from "child_process";
|
|
43455
|
-
import {
|
|
43456
|
-
import {
|
|
43457
|
-
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
43458
|
-
import { homedir as homedir9 } from "os";
|
|
43459
|
-
function tryWhich(executableName) {
|
|
43460
|
-
const pathEnv = process.env.PATH ?? "";
|
|
43461
|
-
const sep = process.platform === "win32" ? ";" : ":";
|
|
43462
|
-
for (const dir of pathEnv.split(sep)) {
|
|
43463
|
-
if (!dir)
|
|
43464
|
-
continue;
|
|
43465
|
-
const candidate = join14(dir, executableName);
|
|
43466
|
-
if (existsSync10(candidate)) {
|
|
43467
|
-
return candidate;
|
|
43468
|
-
}
|
|
43469
|
-
if (process.platform === "win32") {
|
|
43470
|
-
for (const ext of [".cmd", ".exe", ".bat"]) {
|
|
43471
|
-
const withExt = candidate + ext;
|
|
43472
|
-
if (existsSync10(withExt))
|
|
43473
|
-
return withExt;
|
|
43474
|
-
}
|
|
43475
|
-
}
|
|
43476
|
-
}
|
|
43477
|
-
return null;
|
|
43478
|
-
}
|
|
43479
|
-
function findNodeModulesRuntimeBin() {
|
|
43480
|
-
const runtimeBinRel = join14("node_modules", "@openscout", "runtime", "bin", "openscout-runtime.mjs");
|
|
43481
|
-
let dir = dirname8(fileURLToPath6(import.meta.url));
|
|
43482
|
-
for (let i = 0;i < 24; i++) {
|
|
43483
|
-
const candidate = join14(dir, runtimeBinRel);
|
|
43484
|
-
if (existsSync10(candidate))
|
|
43485
|
-
return candidate;
|
|
43486
|
-
const parent = dirname8(dir);
|
|
43487
|
-
if (parent === dir)
|
|
43488
|
-
break;
|
|
43489
|
-
dir = parent;
|
|
43490
|
-
}
|
|
43491
|
-
const bunGlobal = join14(homedir9(), ".bun", "install", "global", "node_modules", "@openscout", "runtime", "bin", "openscout-runtime.mjs");
|
|
43492
|
-
if (existsSync10(bunGlobal))
|
|
43493
|
-
return bunGlobal;
|
|
43494
|
-
return null;
|
|
43495
|
-
}
|
|
43496
|
-
function findMonorepoOpenscoutRuntimeBin() {
|
|
43497
|
-
let dir = process.cwd();
|
|
43498
|
-
for (let i = 0;i < 24; i++) {
|
|
43499
|
-
const candidate = join14(dir, "packages", "runtime", "bin", "openscout-runtime.mjs");
|
|
43500
|
-
if (existsSync10(candidate)) {
|
|
43501
|
-
return candidate;
|
|
43502
|
-
}
|
|
43503
|
-
const parent = dirname8(dir);
|
|
43504
|
-
if (parent === dir)
|
|
43505
|
-
break;
|
|
43506
|
-
dir = parent;
|
|
43507
|
-
}
|
|
43508
|
-
return null;
|
|
43509
|
-
}
|
|
43822
|
+
import { dirname as dirname9 } from "path";
|
|
43823
|
+
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
43510
43824
|
function resolveJavaScriptRuntimeExecutable() {
|
|
43511
|
-
const
|
|
43512
|
-
|
|
43513
|
-
|
|
43514
|
-
|
|
43515
|
-
|
|
43516
|
-
|
|
43517
|
-
|
|
43518
|
-
|
|
43519
|
-
}
|
|
43520
|
-
throw new Error(`OPENSCOUT_RUNTIME_NODE_BIN is set but not found: ${explicit}`);
|
|
43521
|
-
}
|
|
43522
|
-
const execBase = basename6(process.execPath).toLowerCase();
|
|
43523
|
-
if (execBase.startsWith("node") || execBase.startsWith("bun")) {
|
|
43524
|
-
return process.execPath;
|
|
43525
|
-
}
|
|
43526
|
-
const nodeOnPath = tryWhich("node");
|
|
43527
|
-
if (nodeOnPath) {
|
|
43528
|
-
return nodeOnPath;
|
|
43529
|
-
}
|
|
43530
|
-
const bunOnPath = tryWhich("bun");
|
|
43531
|
-
if (bunOnPath) {
|
|
43532
|
-
return bunOnPath;
|
|
43825
|
+
const runtime = resolveJavaScriptRuntime({
|
|
43826
|
+
env: process.env,
|
|
43827
|
+
explicitEnvKeys: ["OPENSCOUT_RUNTIME_NODE_BIN"],
|
|
43828
|
+
allowNode: true,
|
|
43829
|
+
allowBun: true
|
|
43830
|
+
});
|
|
43831
|
+
if (runtime) {
|
|
43832
|
+
return runtime.path;
|
|
43533
43833
|
}
|
|
43534
43834
|
throw new Error("No JavaScript runtime found for openscout-runtime script entry. Install Node.js or set OPENSCOUT_RUNTIME_NODE_BIN.");
|
|
43535
43835
|
}
|
|
43536
43836
|
function resolveRuntimeServiceEntrypoint() {
|
|
43537
|
-
const
|
|
43538
|
-
|
|
43539
|
-
|
|
43540
|
-
|
|
43541
|
-
|
|
43542
|
-
|
|
43543
|
-
|
|
43544
|
-
return found;
|
|
43545
|
-
}
|
|
43546
|
-
throw new Error(`OPENSCOUT_RUNTIME_BIN is set but not found: ${explicit}`);
|
|
43547
|
-
}
|
|
43548
|
-
const onPath = tryWhich("openscout-runtime");
|
|
43549
|
-
if (onPath) {
|
|
43550
|
-
return onPath;
|
|
43837
|
+
const installedExecutable = resolveExecutableFromSearch({
|
|
43838
|
+
env: process.env,
|
|
43839
|
+
envKeys: ["OPENSCOUT_RUNTIME_BIN"],
|
|
43840
|
+
names: ["openscout-runtime"]
|
|
43841
|
+
});
|
|
43842
|
+
if (installedExecutable) {
|
|
43843
|
+
return installedExecutable.path;
|
|
43551
43844
|
}
|
|
43552
|
-
const fromNodeModules =
|
|
43845
|
+
const fromNodeModules = resolveNodeModulesPackageEntrypoint(import.meta.url, ["@openscout", "runtime"], "bin/openscout-runtime.mjs");
|
|
43553
43846
|
if (fromNodeModules) {
|
|
43554
43847
|
return fromNodeModules;
|
|
43555
43848
|
}
|
|
43556
|
-
const
|
|
43557
|
-
|
|
43558
|
-
|
|
43849
|
+
const repoRoot = resolveOpenScoutRepoRoot({
|
|
43850
|
+
startDirectories: [
|
|
43851
|
+
process.env.OPENSCOUT_SETUP_CWD,
|
|
43852
|
+
process.cwd(),
|
|
43853
|
+
dirname9(fileURLToPath7(import.meta.url))
|
|
43854
|
+
]
|
|
43855
|
+
});
|
|
43856
|
+
const repoEntrypoint = resolveRepoEntrypoint(repoRoot, "packages/runtime/bin/openscout-runtime.mjs");
|
|
43857
|
+
if (repoEntrypoint) {
|
|
43858
|
+
return repoEntrypoint;
|
|
43559
43859
|
}
|
|
43560
43860
|
throw new Error("openscout-runtime not found on PATH. Install @openscout/runtime (e.g. npm i -g @openscout/runtime) or set OPENSCOUT_RUNTIME_BIN.");
|
|
43561
43861
|
}
|
|
@@ -43624,12 +43924,14 @@ async function getRuntimeBrokerServiceStatus(options = {}) {
|
|
|
43624
43924
|
return inflightBrokerStatus;
|
|
43625
43925
|
}
|
|
43626
43926
|
var BROKER_STATUS_CACHE_TTL_MS = 2000, cachedBrokerStatus = null, inflightBrokerStatus = null;
|
|
43627
|
-
var init_runtime_service_client = () => {
|
|
43927
|
+
var init_runtime_service_client = __esm(() => {
|
|
43928
|
+
init_tool_resolution();
|
|
43929
|
+
});
|
|
43628
43930
|
|
|
43629
43931
|
// ../../apps/desktop/src/core/setup/command-lock.ts
|
|
43630
|
-
import { mkdir as mkdir8, open, readFile as
|
|
43932
|
+
import { mkdir as mkdir8, open, readFile as readFile9, rm as rm6 } from "fs/promises";
|
|
43631
43933
|
import { hostname as hostname4 } from "os";
|
|
43632
|
-
import { dirname as
|
|
43934
|
+
import { dirname as dirname10, join as join15 } from "path";
|
|
43633
43935
|
function scoutCoreCommandLockPath() {
|
|
43634
43936
|
return join15(resolveOpenScoutSupportPaths().runtimeDirectory, "locks", SCOUT_CORE_COMMAND_LOCK_FILE);
|
|
43635
43937
|
}
|
|
@@ -43655,7 +43957,7 @@ function isProcessAlive(pid) {
|
|
|
43655
43957
|
}
|
|
43656
43958
|
async function readLockPayload(lockPath) {
|
|
43657
43959
|
try {
|
|
43658
|
-
const raw = JSON.parse(await
|
|
43960
|
+
const raw = JSON.parse(await readFile9(lockPath, "utf8"));
|
|
43659
43961
|
if ((raw.command === "setup" || raw.command === "doctor" || raw.command === "runtimes") && typeof raw.pid === "number" && typeof raw.startedAt === "number" && typeof raw.host === "string") {
|
|
43660
43962
|
return {
|
|
43661
43963
|
command: raw.command,
|
|
@@ -43671,7 +43973,7 @@ async function readLockPayload(lockPath) {
|
|
|
43671
43973
|
}
|
|
43672
43974
|
async function acquireScoutCoreCommandLock(command) {
|
|
43673
43975
|
const lockPath = scoutCoreCommandLockPath();
|
|
43674
|
-
await mkdir8(
|
|
43976
|
+
await mkdir8(dirname10(lockPath), { recursive: true });
|
|
43675
43977
|
for (let attempt = 0;attempt < 2; attempt += 1) {
|
|
43676
43978
|
const payload = {
|
|
43677
43979
|
command,
|
|
@@ -43814,8 +44116,8 @@ var init_service3 = __esm(() => {
|
|
|
43814
44116
|
|
|
43815
44117
|
// ../../apps/desktop/src/shared/paths.ts
|
|
43816
44118
|
import { existsSync as existsSync11, readFileSync as readFileSync6 } from "fs";
|
|
43817
|
-
import { dirname as
|
|
43818
|
-
import { fileURLToPath as
|
|
44119
|
+
import { dirname as dirname11, join as join16, resolve as resolve11 } from "path";
|
|
44120
|
+
import { fileURLToPath as fileURLToPath8 } from "url";
|
|
43819
44121
|
function looksLikeWorkspaceRoot(candidate) {
|
|
43820
44122
|
const packageJsonPath = join16(candidate, "package.json");
|
|
43821
44123
|
if (!existsSync11(packageJsonPath)) {
|
|
@@ -43844,12 +44146,12 @@ function looksLikeSourceAppRoot(candidate) {
|
|
|
43844
44146
|
return existsSync11(join16(candidate, "bin", "scout.ts"));
|
|
43845
44147
|
}
|
|
43846
44148
|
function findMatchingAncestor(startDirectory, predicate) {
|
|
43847
|
-
let current =
|
|
44149
|
+
let current = resolve11(startDirectory);
|
|
43848
44150
|
while (true) {
|
|
43849
44151
|
if (predicate(current)) {
|
|
43850
44152
|
return current;
|
|
43851
44153
|
}
|
|
43852
|
-
const parent =
|
|
44154
|
+
const parent = dirname11(current);
|
|
43853
44155
|
if (parent === current) {
|
|
43854
44156
|
return null;
|
|
43855
44157
|
}
|
|
@@ -43857,7 +44159,7 @@ function findMatchingAncestor(startDirectory, predicate) {
|
|
|
43857
44159
|
}
|
|
43858
44160
|
}
|
|
43859
44161
|
function defaultModuleDirectory() {
|
|
43860
|
-
return
|
|
44162
|
+
return dirname11(fileURLToPath8(import.meta.url));
|
|
43861
44163
|
}
|
|
43862
44164
|
function uniqueResolutionStarts(options) {
|
|
43863
44165
|
const starts = [
|
|
@@ -43866,7 +44168,7 @@ function uniqueResolutionStarts(options) {
|
|
|
43866
44168
|
process.cwd(),
|
|
43867
44169
|
options.moduleDirectory?.trim()
|
|
43868
44170
|
];
|
|
43869
|
-
const resolvedStarts = starts.filter((value) => Boolean(value)).map((value) =>
|
|
44171
|
+
const resolvedStarts = starts.filter((value) => Boolean(value)).map((value) => resolve11(value));
|
|
43870
44172
|
return [...new Set(resolvedStarts)];
|
|
43871
44173
|
}
|
|
43872
44174
|
function resolveScoutWorkspaceRoot(options = {}) {
|
|
@@ -43895,7 +44197,7 @@ function resolveScoutAppRoot(options = {}) {
|
|
|
43895
44197
|
}
|
|
43896
44198
|
const workspaceRoot = resolveScoutWorkspaceRoot(options);
|
|
43897
44199
|
for (const relativePath of [["apps", "desktop"], ["apps", "scout"], ["packages", "cli"]]) {
|
|
43898
|
-
const candidate =
|
|
44200
|
+
const candidate = resolve11(workspaceRoot, ...relativePath);
|
|
43899
44201
|
if (looksLikeSourceAppRoot(candidate)) {
|
|
43900
44202
|
return candidate;
|
|
43901
44203
|
}
|
|
@@ -44265,7 +44567,7 @@ import {
|
|
|
44265
44567
|
writeFileSync as writeFileSync4
|
|
44266
44568
|
} from "fs";
|
|
44267
44569
|
import { homedir as homedir10 } from "os";
|
|
44268
|
-
import { dirname as
|
|
44570
|
+
import { dirname as dirname12, join as join18 } from "path";
|
|
44269
44571
|
function localConfigHome() {
|
|
44270
44572
|
return process.env.OPENSCOUT_HOME ?? join18(homedir10(), ".openscout");
|
|
44271
44573
|
}
|
|
@@ -44307,9 +44609,12 @@ function validateLocalConfig(input) {
|
|
|
44307
44609
|
function isValidPort(value) {
|
|
44308
44610
|
return typeof value === "number" && Number.isInteger(value) && value > 0 && value < 65536;
|
|
44309
44611
|
}
|
|
44612
|
+
function resolveWebPort() {
|
|
44613
|
+
return loadLocalConfig().ports?.web ?? DEFAULT_LOCAL_CONFIG.ports.web;
|
|
44614
|
+
}
|
|
44310
44615
|
function writeLocalConfig(config2) {
|
|
44311
44616
|
const configPath = localConfigPath();
|
|
44312
|
-
mkdirSync4(
|
|
44617
|
+
mkdirSync4(dirname12(configPath), { recursive: true });
|
|
44313
44618
|
const body = JSON.stringify({ ...config2, version: LOCAL_CONFIG_VERSION }, null, 2) + `
|
|
44314
44619
|
`;
|
|
44315
44620
|
const tmp = `${configPath}.tmp`;
|
|
@@ -44742,7 +45047,7 @@ class McpServer {
|
|
|
44742
45047
|
let task = createTaskResult.task;
|
|
44743
45048
|
const pollInterval = task.pollInterval ?? 5000;
|
|
44744
45049
|
while (task.status !== "completed" && task.status !== "failed" && task.status !== "cancelled") {
|
|
44745
|
-
await new Promise((
|
|
45050
|
+
await new Promise((resolve12) => setTimeout(resolve12, pollInterval));
|
|
44746
45051
|
const updatedTask = await extra.taskStore.getTask(taskId);
|
|
44747
45052
|
if (!updatedTask) {
|
|
44748
45053
|
throw new McpError(ErrorCode.InternalError, `Task ${taskId} not found during polling`);
|
|
@@ -45291,7 +45596,41 @@ var init_mcp = __esm(() => {
|
|
|
45291
45596
|
});
|
|
45292
45597
|
|
|
45293
45598
|
// ../../apps/desktop/src/core/mcp/scout-mcp.ts
|
|
45294
|
-
import { basename as basename7, resolve as
|
|
45599
|
+
import { basename as basename7, resolve as resolve12 } from "path";
|
|
45600
|
+
function createAgentPickerFieldMeta(input) {
|
|
45601
|
+
return {
|
|
45602
|
+
kind: "agent-picker",
|
|
45603
|
+
selection: input.selection,
|
|
45604
|
+
sourceTool: "agents_search",
|
|
45605
|
+
resolveTool: input.resolveTool,
|
|
45606
|
+
sourceArguments: {
|
|
45607
|
+
query: { from: "value" },
|
|
45608
|
+
currentDirectory: { fromToolArgument: "currentDirectory" }
|
|
45609
|
+
},
|
|
45610
|
+
resultPath: ["structuredContent", "candidates"],
|
|
45611
|
+
valueField: input.valueField,
|
|
45612
|
+
labelField: "label",
|
|
45613
|
+
descriptionField: "displayName",
|
|
45614
|
+
badgeFields: ["harness", "workspace", "node"],
|
|
45615
|
+
icon: scoutAgentAvatarMeta,
|
|
45616
|
+
search: {
|
|
45617
|
+
minQueryLength: 0,
|
|
45618
|
+
debounceMs: 100,
|
|
45619
|
+
cacheBy: ["currentDirectory"]
|
|
45620
|
+
}
|
|
45621
|
+
};
|
|
45622
|
+
}
|
|
45623
|
+
function createToolUiMeta(fields) {
|
|
45624
|
+
const value = {
|
|
45625
|
+
icon: scoutAgentToolIconMeta
|
|
45626
|
+
};
|
|
45627
|
+
if (fields && Object.keys(fields).length > 0) {
|
|
45628
|
+
value.fields = fields;
|
|
45629
|
+
}
|
|
45630
|
+
return {
|
|
45631
|
+
[SCOUT_MCP_UI_META_KEY]: value
|
|
45632
|
+
};
|
|
45633
|
+
}
|
|
45295
45634
|
function createTextContent(value) {
|
|
45296
45635
|
return [{ type: "text", text: JSON.stringify(value, null, 2) }];
|
|
45297
45636
|
}
|
|
@@ -45302,9 +45641,9 @@ function isSameProjectRoot(left, right) {
|
|
|
45302
45641
|
if (!left || !right) {
|
|
45303
45642
|
return false;
|
|
45304
45643
|
}
|
|
45305
|
-
return
|
|
45644
|
+
return resolve12(left) === resolve12(right);
|
|
45306
45645
|
}
|
|
45307
|
-
function
|
|
45646
|
+
function matchesObviousProjectLocalAlias(value, query) {
|
|
45308
45647
|
const normalized = normalizeSearchValue(value);
|
|
45309
45648
|
if (!normalized || !query) {
|
|
45310
45649
|
return false;
|
|
@@ -45324,7 +45663,7 @@ function scoreProjectLocalCandidate(candidate, currentProjectRoot, query) {
|
|
|
45324
45663
|
candidate.displayName,
|
|
45325
45664
|
candidate.agentId
|
|
45326
45665
|
];
|
|
45327
|
-
const matches = values.filter((value) =>
|
|
45666
|
+
const matches = values.filter((value) => matchesObviousProjectLocalAlias(value, query));
|
|
45328
45667
|
if (matches.length === 0) {
|
|
45329
45668
|
return -1;
|
|
45330
45669
|
}
|
|
@@ -45803,7 +46142,7 @@ function createScoutMcpServer(options) {
|
|
|
45803
46142
|
const resolvedCurrentDirectory = resolveToolCurrentDirectory(currentDirectory, options.defaultCurrentDirectory);
|
|
45804
46143
|
const resolvedSenderId = await deps.resolveSenderId(senderId, resolvedCurrentDirectory, env);
|
|
45805
46144
|
const card = await deps.createAgentCard({
|
|
45806
|
-
projectPath:
|
|
46145
|
+
projectPath: resolve12(projectPath?.trim() || resolvedCurrentDirectory),
|
|
45807
46146
|
agentName: agentName?.trim() || undefined,
|
|
45808
46147
|
displayName: displayName?.trim() || undefined,
|
|
45809
46148
|
harness,
|
|
@@ -45825,7 +46164,7 @@ function createScoutMcpServer(options) {
|
|
|
45825
46164
|
title: "Search Scout Agents",
|
|
45826
46165
|
description: "Search the live Scout broker and discovered agent inventory for @mention candidates. Use this after whoami when you know roughly who you need but do not yet have an exact handle.",
|
|
45827
46166
|
inputSchema: object2({
|
|
45828
|
-
query: string2().optional(),
|
|
46167
|
+
query: string2().describe("Partial handle, label, or display name to search for").optional(),
|
|
45829
46168
|
currentDirectory: string2().optional(),
|
|
45830
46169
|
limit: number2().int().min(1).max(50).optional()
|
|
45831
46170
|
}),
|
|
@@ -45835,7 +46174,8 @@ function createScoutMcpServer(options) {
|
|
|
45835
46174
|
idempotentHint: true,
|
|
45836
46175
|
destructiveHint: false,
|
|
45837
46176
|
openWorldHint: false
|
|
45838
|
-
}
|
|
46177
|
+
},
|
|
46178
|
+
_meta: createToolUiMeta()
|
|
45839
46179
|
}, async ({ query, currentDirectory, limit }) => {
|
|
45840
46180
|
const resolvedCurrentDirectory = resolveToolCurrentDirectory(currentDirectory, options.defaultCurrentDirectory);
|
|
45841
46181
|
const candidates = await deps.searchAgents({
|
|
@@ -45857,7 +46197,7 @@ function createScoutMcpServer(options) {
|
|
|
45857
46197
|
title: "Resolve Scout Agent",
|
|
45858
46198
|
description: "Resolve one exact Scout agent handle or return ambiguity details. Use this before send or ask when a short handle may be ambiguous.",
|
|
45859
46199
|
inputSchema: object2({
|
|
45860
|
-
label: string2().min(1),
|
|
46200
|
+
label: string2().min(1).describe("Scout agent handle or selector, such as @talkie"),
|
|
45861
46201
|
currentDirectory: string2().optional()
|
|
45862
46202
|
}),
|
|
45863
46203
|
outputSchema: resolveResultSchema,
|
|
@@ -45866,7 +46206,8 @@ function createScoutMcpServer(options) {
|
|
|
45866
46206
|
idempotentHint: true,
|
|
45867
46207
|
destructiveHint: false,
|
|
45868
46208
|
openWorldHint: false
|
|
45869
|
-
}
|
|
46209
|
+
},
|
|
46210
|
+
_meta: createToolUiMeta()
|
|
45870
46211
|
}, async ({ label, currentDirectory }) => {
|
|
45871
46212
|
const resolvedCurrentDirectory = resolveToolCurrentDirectory(currentDirectory, options.defaultCurrentDirectory);
|
|
45872
46213
|
const resolution = await deps.resolveAgent({
|
|
@@ -45892,10 +46233,10 @@ function createScoutMcpServer(options) {
|
|
|
45892
46233
|
body: string2().min(1),
|
|
45893
46234
|
currentDirectory: string2().optional(),
|
|
45894
46235
|
senderId: string2().optional(),
|
|
45895
|
-
targetLabel:
|
|
46236
|
+
targetLabel: targetLabelInputSchema,
|
|
45896
46237
|
channel: string2().optional(),
|
|
45897
46238
|
shouldSpeak: boolean2().optional(),
|
|
45898
|
-
mentionAgentIds:
|
|
46239
|
+
mentionAgentIds: mentionAgentIdsInputSchema
|
|
45899
46240
|
}),
|
|
45900
46241
|
outputSchema: sendResultSchema,
|
|
45901
46242
|
annotations: {
|
|
@@ -45903,7 +46244,18 @@ function createScoutMcpServer(options) {
|
|
|
45903
46244
|
idempotentHint: false,
|
|
45904
46245
|
destructiveHint: false,
|
|
45905
46246
|
openWorldHint: false
|
|
45906
|
-
}
|
|
46247
|
+
},
|
|
46248
|
+
_meta: createToolUiMeta({
|
|
46249
|
+
targetLabel: createAgentPickerFieldMeta({
|
|
46250
|
+
selection: "single",
|
|
46251
|
+
valueField: "label",
|
|
46252
|
+
resolveTool: "agents_resolve"
|
|
46253
|
+
}),
|
|
46254
|
+
mentionAgentIds: createAgentPickerFieldMeta({
|
|
46255
|
+
selection: "multiple",
|
|
46256
|
+
valueField: "agentId"
|
|
46257
|
+
})
|
|
46258
|
+
})
|
|
45907
46259
|
}, async ({
|
|
45908
46260
|
body,
|
|
45909
46261
|
currentDirectory,
|
|
@@ -45937,6 +46289,7 @@ function createScoutMcpServer(options) {
|
|
|
45937
46289
|
messageId: result2.messageId ?? null,
|
|
45938
46290
|
invokedTargetIds: result2.invokedTargetIds,
|
|
45939
46291
|
unresolvedTargetIds: result2.unresolvedTargetIds,
|
|
46292
|
+
targetDiagnostic: result2.targetDiagnostic ?? null,
|
|
45940
46293
|
routeKind: result2.routeKind ?? null,
|
|
45941
46294
|
routingError: result2.routingError ?? null
|
|
45942
46295
|
};
|
|
@@ -45963,6 +46316,7 @@ function createScoutMcpServer(options) {
|
|
|
45963
46316
|
messageId: result2.messageId ?? null,
|
|
45964
46317
|
invokedTargetIds: result2.invokedTargets,
|
|
45965
46318
|
unresolvedTargetIds: result2.unresolvedTargets,
|
|
46319
|
+
targetDiagnostic: result2.targetDiagnostic ?? null,
|
|
45966
46320
|
routeKind: result2.routeKind ?? null,
|
|
45967
46321
|
routingError: result2.routingError ?? null
|
|
45968
46322
|
};
|
|
@@ -45987,6 +46341,7 @@ function createScoutMcpServer(options) {
|
|
|
45987
46341
|
messageId: result.messageId ?? null,
|
|
45988
46342
|
invokedTargetIds: result.invokedTargets,
|
|
45989
46343
|
unresolvedTargetIds: result.unresolvedTargets,
|
|
46344
|
+
targetDiagnostic: result.targetDiagnostic ?? null,
|
|
45990
46345
|
routeKind: result.routeKind ?? null,
|
|
45991
46346
|
routingError: result.routingError ?? null
|
|
45992
46347
|
};
|
|
@@ -46002,8 +46357,8 @@ function createScoutMcpServer(options) {
|
|
|
46002
46357
|
body: string2().min(1),
|
|
46003
46358
|
currentDirectory: string2().optional(),
|
|
46004
46359
|
senderId: string2().optional(),
|
|
46005
|
-
targetAgentId:
|
|
46006
|
-
targetLabel:
|
|
46360
|
+
targetAgentId: targetAgentIdInputSchema,
|
|
46361
|
+
targetLabel: targetLabelInputSchema,
|
|
46007
46362
|
workItem: workItemInputSchema.optional(),
|
|
46008
46363
|
channel: string2().optional(),
|
|
46009
46364
|
shouldSpeak: boolean2().optional(),
|
|
@@ -46019,7 +46374,18 @@ function createScoutMcpServer(options) {
|
|
|
46019
46374
|
idempotentHint: false,
|
|
46020
46375
|
destructiveHint: false,
|
|
46021
46376
|
openWorldHint: false
|
|
46022
|
-
}
|
|
46377
|
+
},
|
|
46378
|
+
_meta: createToolUiMeta({
|
|
46379
|
+
targetAgentId: createAgentPickerFieldMeta({
|
|
46380
|
+
selection: "single",
|
|
46381
|
+
valueField: "agentId"
|
|
46382
|
+
}),
|
|
46383
|
+
targetLabel: createAgentPickerFieldMeta({
|
|
46384
|
+
selection: "single",
|
|
46385
|
+
valueField: "label",
|
|
46386
|
+
resolveTool: "agents_resolve"
|
|
46387
|
+
})
|
|
46388
|
+
})
|
|
46023
46389
|
}, async ({
|
|
46024
46390
|
body,
|
|
46025
46391
|
currentDirectory,
|
|
@@ -46151,7 +46517,7 @@ async function runScoutMcpServer(options) {
|
|
|
46151
46517
|
const transport = new StdioServerTransport;
|
|
46152
46518
|
await server.connect(transport);
|
|
46153
46519
|
}
|
|
46154
|
-
var AGENT_STATE_VALUES, REGISTRATION_KIND_VALUES, RESOLVE_KIND_VALUES, MESSAGE_ROUTE_KIND_VALUES, MESSAGE_ROUTING_ERROR_VALUES, LOCAL_AGENT_HARNESS_VALUES, flightSchema, trackedWorkItemSchema, workItemInputSchema, waitingOnSchema, progressSchema, workItemUpdateSchema, agentCandidateSchema, scoutReturnAddressSchema, scoutAgentCardSchema, whoAmISchema, searchResultSchema, resolveResultSchema, sendResultSchema, cardCreateResultSchema, askResultSchema, workUpdateResultSchema;
|
|
46520
|
+
var AGENT_STATE_VALUES, REGISTRATION_KIND_VALUES, RESOLVE_KIND_VALUES, MESSAGE_ROUTE_KIND_VALUES, MESSAGE_ROUTING_ERROR_VALUES, LOCAL_AGENT_HARNESS_VALUES, SCOUT_MCP_UI_META_KEY = "openscout/ui", scoutAgentToolIconMeta, scoutAgentAvatarMeta, targetLabelInputSchema, targetAgentIdInputSchema, mentionAgentIdsInputSchema, flightSchema, trackedWorkItemSchema, workItemInputSchema, waitingOnSchema, progressSchema, workItemUpdateSchema, agentCandidateSchema, scoutReturnAddressSchema, scoutAgentCardSchema, whoAmISchema, searchResultSchema, resolveResultSchema, sendResultSchema, cardCreateResultSchema, askResultSchema, workUpdateResultSchema;
|
|
46155
46521
|
var init_scout_mcp = __esm(async () => {
|
|
46156
46522
|
init_mcp();
|
|
46157
46523
|
init_stdio2();
|
|
@@ -46182,6 +46548,21 @@ var init_scout_mcp = __esm(async () => {
|
|
|
46182
46548
|
"multi_target_requires_explicit_channel"
|
|
46183
46549
|
];
|
|
46184
46550
|
LOCAL_AGENT_HARNESS_VALUES = ["claude", "codex"];
|
|
46551
|
+
scoutAgentToolIconMeta = {
|
|
46552
|
+
kind: "semantic",
|
|
46553
|
+
name: "agent",
|
|
46554
|
+
fallbackGlyph: "@"
|
|
46555
|
+
};
|
|
46556
|
+
scoutAgentAvatarMeta = {
|
|
46557
|
+
kind: "agent-avatar",
|
|
46558
|
+
monogramField: "displayName",
|
|
46559
|
+
fallbackField: "handle",
|
|
46560
|
+
colorSeedField: "agentId",
|
|
46561
|
+
fallbackGlyph: "@"
|
|
46562
|
+
};
|
|
46563
|
+
targetLabelInputSchema = string2().describe("Scout agent handle to contact, such as @talkie").optional();
|
|
46564
|
+
targetAgentIdInputSchema = string2().describe("Exact Scout agent id when already known, such as talkie.master.mini").optional();
|
|
46565
|
+
mentionAgentIdsInputSchema = array(string2()).describe("Exact Scout agent ids to target directly when you already know them").optional();
|
|
46185
46566
|
flightSchema = object2({
|
|
46186
46567
|
id: string2(),
|
|
46187
46568
|
invocationId: string2(),
|
|
@@ -46328,6 +46709,7 @@ var init_scout_mcp = __esm(async () => {
|
|
|
46328
46709
|
messageId: string2().nullable(),
|
|
46329
46710
|
invokedTargetIds: array(string2()),
|
|
46330
46711
|
unresolvedTargetIds: array(string2()),
|
|
46712
|
+
targetDiagnostic: object2({}).catchall(unknown()).nullable(),
|
|
46331
46713
|
routeKind: _enum2(MESSAGE_ROUTE_KIND_VALUES).nullable(),
|
|
46332
46714
|
routingError: _enum2(MESSAGE_ROUTING_ERROR_VALUES).nullable()
|
|
46333
46715
|
});
|
|
@@ -46417,8 +46799,8 @@ __export(exports_menu, {
|
|
|
46417
46799
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
46418
46800
|
import { existsSync as existsSync14 } from "fs";
|
|
46419
46801
|
import { homedir as homedir11 } from "os";
|
|
46420
|
-
import { dirname as
|
|
46421
|
-
import { fileURLToPath as
|
|
46802
|
+
import { dirname as dirname13, join as join19, resolve as resolve13 } from "path";
|
|
46803
|
+
import { fileURLToPath as fileURLToPath9 } from "url";
|
|
46422
46804
|
function renderMenuCommandHelp() {
|
|
46423
46805
|
return [
|
|
46424
46806
|
"scout menu \u2014 macOS menu bar app",
|
|
@@ -46501,23 +46883,23 @@ function runProcess(command, args, options) {
|
|
|
46501
46883
|
};
|
|
46502
46884
|
}
|
|
46503
46885
|
function findRepoMenuHelper(startDirectory) {
|
|
46504
|
-
let current =
|
|
46886
|
+
let current = resolve13(startDirectory);
|
|
46505
46887
|
while (true) {
|
|
46506
46888
|
const candidate = join19(current, "apps", "macos", "bin", "openscout-menu.ts");
|
|
46507
46889
|
if (existsSync14(candidate)) {
|
|
46508
46890
|
return candidate;
|
|
46509
46891
|
}
|
|
46510
|
-
const parent =
|
|
46892
|
+
const parent = dirname13(current);
|
|
46511
46893
|
if (parent === current) {
|
|
46512
46894
|
break;
|
|
46513
46895
|
}
|
|
46514
46896
|
current = parent;
|
|
46515
46897
|
}
|
|
46516
|
-
const sourceRelativeCandidate =
|
|
46898
|
+
const sourceRelativeCandidate = fileURLToPath9(new URL("../../../../macos/bin/openscout-menu.ts", import.meta.url));
|
|
46517
46899
|
return existsSync14(sourceRelativeCandidate) ? sourceRelativeCandidate : null;
|
|
46518
46900
|
}
|
|
46519
46901
|
function resolveRepoBundlePath(helperPath) {
|
|
46520
|
-
return
|
|
46902
|
+
return resolve13(dirname13(helperPath), "..", "dist", MENU_BUNDLE_NAME);
|
|
46521
46903
|
}
|
|
46522
46904
|
function isMenuRunning(env) {
|
|
46523
46905
|
return runProcess("pgrep", ["-x", MENU_PROCESS_NAME], { env, allowFailure: true }).ok;
|
|
@@ -46675,7 +47057,7 @@ var init_menu = __esm(() => {
|
|
|
46675
47057
|
});
|
|
46676
47058
|
|
|
46677
47059
|
// ../runtime/src/tailscale.ts
|
|
46678
|
-
import { readFile as
|
|
47060
|
+
import { readFile as readFile10 } from "fs/promises";
|
|
46679
47061
|
import { execFile } from "child_process";
|
|
46680
47062
|
import { promisify } from "util";
|
|
46681
47063
|
function parseStatusJson(raw) {
|
|
@@ -46715,7 +47097,7 @@ function isBackendRunning(status) {
|
|
|
46715
47097
|
return (status.BackendState ?? "").trim().toLowerCase() === "running";
|
|
46716
47098
|
}
|
|
46717
47099
|
async function readStatusJsonFromFile(filePath) {
|
|
46718
|
-
const raw = await
|
|
47100
|
+
const raw = await readFile10(filePath, "utf8");
|
|
46719
47101
|
return parseStatusJson(raw);
|
|
46720
47102
|
}
|
|
46721
47103
|
async function readStatusJson() {
|
|
@@ -49336,15 +49718,30 @@ function saveTrustedPeer(peer) {
|
|
|
49336
49718
|
function isTrustedPeer(publicKeyHex) {
|
|
49337
49719
|
return loadTrustedPeers().has(publicKeyHex);
|
|
49338
49720
|
}
|
|
49339
|
-
function createQRPayload(bridgePublicKey, relayUrl) {
|
|
49721
|
+
function createQRPayload(bridgePublicKey, relayUrl, fallbackRelayUrls = []) {
|
|
49722
|
+
const fallbackRelays = normalizedRelayUrls(fallbackRelayUrls, relayUrl);
|
|
49340
49723
|
return {
|
|
49341
49724
|
v: QR_VERSION,
|
|
49342
49725
|
relay: relayUrl,
|
|
49726
|
+
...fallbackRelays.length > 0 ? { fallbackRelays } : {},
|
|
49343
49727
|
room: crypto.randomUUID(),
|
|
49344
49728
|
publicKey: bytesToHex2(bridgePublicKey),
|
|
49345
49729
|
expiresAt: Date.now() + QR_EXPIRY_MS
|
|
49346
49730
|
};
|
|
49347
49731
|
}
|
|
49732
|
+
function normalizedRelayUrls(urls, primaryRelayUrl) {
|
|
49733
|
+
const seen = new Set([primaryRelayUrl.trim()]);
|
|
49734
|
+
const normalized = [];
|
|
49735
|
+
for (const url2 of urls) {
|
|
49736
|
+
const trimmed = url2.trim();
|
|
49737
|
+
if (!trimmed || seen.has(trimmed)) {
|
|
49738
|
+
continue;
|
|
49739
|
+
}
|
|
49740
|
+
seen.add(trimmed);
|
|
49741
|
+
normalized.push(trimmed);
|
|
49742
|
+
}
|
|
49743
|
+
return normalized;
|
|
49744
|
+
}
|
|
49348
49745
|
function bytesToHex2(bytes) {
|
|
49349
49746
|
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
49350
49747
|
}
|
|
@@ -50639,7 +51036,7 @@ var init_db_queries = __esm(() => {
|
|
|
50639
51036
|
});
|
|
50640
51037
|
|
|
50641
51038
|
// ../../apps/desktop/src/core/mobile/service.ts
|
|
50642
|
-
import { basename as basename8, resolve as
|
|
51039
|
+
import { basename as basename8, resolve as resolve14 } from "path";
|
|
50643
51040
|
function normalizeTimestamp2(value) {
|
|
50644
51041
|
if (!value)
|
|
50645
51042
|
return null;
|
|
@@ -51028,7 +51425,7 @@ async function createScoutSession(input, currentDirectory, deviceId) {
|
|
|
51028
51425
|
if (!rawWorkspaceId) {
|
|
51029
51426
|
throw new Error(`Invalid workspaceId.`);
|
|
51030
51427
|
}
|
|
51031
|
-
const workspaceRoot =
|
|
51428
|
+
const workspaceRoot = resolve14(rawWorkspaceId);
|
|
51032
51429
|
const projectName = basename8(workspaceRoot) || workspaceRoot;
|
|
51033
51430
|
const workspace = {
|
|
51034
51431
|
id: workspaceRoot,
|
|
@@ -52763,7 +53160,7 @@ import { Database as Database2 } from "bun:sqlite";
|
|
|
52763
53160
|
import { mkdirSync as mkdirSync9, readFileSync as readFileSync13 } from "fs";
|
|
52764
53161
|
import { connect as connectHttp2 } from "http2";
|
|
52765
53162
|
import { createPrivateKey, sign as signWithKey } from "crypto";
|
|
52766
|
-
import { dirname as
|
|
53163
|
+
import { dirname as dirname14, join as join25 } from "path";
|
|
52767
53164
|
function resolveControlPlaneDbPath() {
|
|
52768
53165
|
return join25(resolveOpenScoutSupportPaths().controlHome, "control-plane.sqlite");
|
|
52769
53166
|
}
|
|
@@ -52779,7 +53176,7 @@ function writeDb() {
|
|
|
52779
53176
|
dbHandle = null;
|
|
52780
53177
|
}
|
|
52781
53178
|
if (!dbHandle) {
|
|
52782
|
-
mkdirSync9(
|
|
53179
|
+
mkdirSync9(dirname14(nextPath), { recursive: true });
|
|
52783
53180
|
dbHandle = new Database2(nextPath, { create: true });
|
|
52784
53181
|
dbPath = nextPath;
|
|
52785
53182
|
ensureMobilePushSchema(dbHandle);
|
|
@@ -52995,7 +53392,7 @@ async function sendApnsAlertToRegistration(registration, alert) {
|
|
|
52995
53392
|
},
|
|
52996
53393
|
...alert.payload ? { scout: alert.payload } : {}
|
|
52997
53394
|
});
|
|
52998
|
-
return new Promise((
|
|
53395
|
+
return new Promise((resolve15, reject) => {
|
|
52999
53396
|
const client = connectHttp2(authority);
|
|
53000
53397
|
client.once("error", reject);
|
|
53001
53398
|
const request = client.request({
|
|
@@ -53033,7 +53430,7 @@ async function sendApnsAlertToRegistration(registration, alert) {
|
|
|
53033
53430
|
}
|
|
53034
53431
|
}
|
|
53035
53432
|
if (status === 200) {
|
|
53036
|
-
|
|
53433
|
+
resolve15({
|
|
53037
53434
|
delivered: true,
|
|
53038
53435
|
skipped: false,
|
|
53039
53436
|
status,
|
|
@@ -53045,7 +53442,7 @@ async function sendApnsAlertToRegistration(registration, alert) {
|
|
|
53045
53442
|
if (reason === "BadDeviceToken" || reason === "Unregistered") {
|
|
53046
53443
|
deleteMobilePushRegistrationByToken(registration.pushToken);
|
|
53047
53444
|
}
|
|
53048
|
-
|
|
53445
|
+
resolve15({
|
|
53049
53446
|
delivered: false,
|
|
53050
53447
|
skipped: false,
|
|
53051
53448
|
status,
|
|
@@ -53290,23 +53687,23 @@ function bridgeEventIterable(bridge, signal) {
|
|
|
53290
53687
|
return {
|
|
53291
53688
|
[Symbol.asyncIterator]() {
|
|
53292
53689
|
const buffer = [];
|
|
53293
|
-
let
|
|
53690
|
+
let resolve15 = null;
|
|
53294
53691
|
let done = false;
|
|
53295
53692
|
const unsub = bridge.onEvent((event) => {
|
|
53296
53693
|
if (done)
|
|
53297
53694
|
return;
|
|
53298
53695
|
buffer.push(event);
|
|
53299
|
-
if (
|
|
53300
|
-
|
|
53301
|
-
|
|
53696
|
+
if (resolve15) {
|
|
53697
|
+
resolve15();
|
|
53698
|
+
resolve15 = null;
|
|
53302
53699
|
}
|
|
53303
53700
|
});
|
|
53304
53701
|
const cleanup = () => {
|
|
53305
53702
|
done = true;
|
|
53306
53703
|
unsub();
|
|
53307
|
-
if (
|
|
53308
|
-
|
|
53309
|
-
|
|
53704
|
+
if (resolve15) {
|
|
53705
|
+
resolve15();
|
|
53706
|
+
resolve15 = null;
|
|
53310
53707
|
}
|
|
53311
53708
|
};
|
|
53312
53709
|
signal?.addEventListener("abort", cleanup, { once: true });
|
|
@@ -53319,7 +53716,7 @@ function bridgeEventIterable(bridge, signal) {
|
|
|
53319
53716
|
return { done: false, value: buffer.shift() };
|
|
53320
53717
|
}
|
|
53321
53718
|
await new Promise((r) => {
|
|
53322
|
-
|
|
53719
|
+
resolve15 = r;
|
|
53323
53720
|
});
|
|
53324
53721
|
}
|
|
53325
53722
|
},
|
|
@@ -54037,7 +54434,8 @@ var init_router = __esm(async () => {
|
|
|
54037
54434
|
// ../../apps/desktop/src/core/pairing/runtime/bridge/relay-client.ts
|
|
54038
54435
|
function connectToRelay(relayUrl, identity2, bridge, options = {}) {
|
|
54039
54436
|
const { secure = true, events: events2 } = options;
|
|
54040
|
-
const
|
|
54437
|
+
const publicRelayUrl = options.publicRelayUrl?.trim() || relayUrl;
|
|
54438
|
+
const qrPayload = createQRPayload(identity2.publicKey, publicRelayUrl, options.fallbackRelayUrls);
|
|
54041
54439
|
let ws = null;
|
|
54042
54440
|
let eventUnsub = null;
|
|
54043
54441
|
let stopped = false;
|
|
@@ -54051,12 +54449,12 @@ function connectToRelay(relayUrl, identity2, bridge, options = {}) {
|
|
|
54051
54449
|
const bridgeKeyHex = bytesToHex2(identity2.publicKey);
|
|
54052
54450
|
const url2 = buildRelayUrl(relayUrl, qrPayload.room, bridgeKeyHex);
|
|
54053
54451
|
console.log(`[relay-client] connecting to relay (room: ${qrPayload.room})`);
|
|
54054
|
-
events2?.onConnecting?.({ relayUrl, room: qrPayload.room });
|
|
54452
|
+
events2?.onConnecting?.({ relayUrl: publicRelayUrl, room: qrPayload.room });
|
|
54055
54453
|
ws = new WebSocket(url2, relayWebSocketOptions(relayUrl));
|
|
54056
54454
|
ws.addEventListener("open", () => {
|
|
54057
54455
|
console.log(`[relay-client] connected to relay (room: ${qrPayload.room})`);
|
|
54058
54456
|
backoff = INITIAL_BACKOFF_MS;
|
|
54059
|
-
events2?.onConnected?.({ relayUrl, room: qrPayload.room });
|
|
54457
|
+
events2?.onConnected?.({ relayUrl: publicRelayUrl, room: qrPayload.room });
|
|
54060
54458
|
});
|
|
54061
54459
|
ws.addEventListener("message", (event) => {
|
|
54062
54460
|
handleRelaySocketMessage(event.data);
|
|
@@ -54064,7 +54462,7 @@ function connectToRelay(relayUrl, identity2, bridge, options = {}) {
|
|
|
54064
54462
|
ws.addEventListener("close", (event) => {
|
|
54065
54463
|
console.log(`[relay-client] disconnected (code: ${event.code}, reason: ${event.reason})`);
|
|
54066
54464
|
events2?.onClosed?.({
|
|
54067
|
-
relayUrl,
|
|
54465
|
+
relayUrl: publicRelayUrl,
|
|
54068
54466
|
room: qrPayload.room,
|
|
54069
54467
|
code: event.code,
|
|
54070
54468
|
reason: event.reason
|
|
@@ -54075,7 +54473,7 @@ function connectToRelay(relayUrl, identity2, bridge, options = {}) {
|
|
|
54075
54473
|
ws.addEventListener("error", () => {
|
|
54076
54474
|
const error48 = new Error("Relay websocket error");
|
|
54077
54475
|
console.error("[relay-client] connection error");
|
|
54078
|
-
events2?.onError?.({ relayUrl, room: qrPayload.room, error: error48 });
|
|
54476
|
+
events2?.onError?.({ relayUrl: publicRelayUrl, room: qrPayload.room, error: error48 });
|
|
54079
54477
|
});
|
|
54080
54478
|
}
|
|
54081
54479
|
function handleRelaySocketMessage(raw) {
|
|
@@ -54129,7 +54527,7 @@ function connectToRelay(relayUrl, identity2, bridge, options = {}) {
|
|
|
54129
54527
|
replaceOlderPeerForSameDevice(peer);
|
|
54130
54528
|
ensureBridgeEventSubscription();
|
|
54131
54529
|
console.log(`[relay-client] secure handshake complete (peer: ${pubHex.slice(0, 12)}..., device: ${peer.deviceId}, client: ${clientId})`);
|
|
54132
|
-
events2?.onPaired?.({ relayUrl, room: qrPayload.room, remotePublicKey });
|
|
54530
|
+
events2?.onPaired?.({ relayUrl: publicRelayUrl, room: qrPayload.room, remotePublicKey });
|
|
54133
54531
|
sendExistingSessions((json2) => {
|
|
54134
54532
|
if (peer.transport.isReady()) {
|
|
54135
54533
|
peer.transport.send(json2);
|
|
@@ -54142,7 +54540,7 @@ function connectToRelay(relayUrl, identity2, bridge, options = {}) {
|
|
|
54142
54540
|
onError: (err) => {
|
|
54143
54541
|
console.error("[relay-client] secure transport error:", err.message);
|
|
54144
54542
|
log.error("trns:cry", `decrypt failed for ${clientId} \u2014 resetting handshake: ${err.message}`);
|
|
54145
|
-
events2?.onError?.({ relayUrl, room: qrPayload.room, error: err });
|
|
54543
|
+
events2?.onError?.({ relayUrl: publicRelayUrl, room: qrPayload.room, error: err });
|
|
54146
54544
|
sendRelayClose(clientId, 4002, "Transport reset");
|
|
54147
54545
|
teardownSecurePeer(clientId);
|
|
54148
54546
|
},
|
|
@@ -54341,7 +54739,7 @@ function connectToRelay(relayUrl, identity2, bridge, options = {}) {
|
|
|
54341
54739
|
if (stopped)
|
|
54342
54740
|
return;
|
|
54343
54741
|
console.log(`[relay-client] reconnecting in ${backoff}ms...`);
|
|
54344
|
-
events2?.onReconnectScheduled?.({ relayUrl, room: qrPayload.room, delayMs: backoff });
|
|
54742
|
+
events2?.onReconnectScheduled?.({ relayUrl: publicRelayUrl, room: qrPayload.room, delayMs: backoff });
|
|
54345
54743
|
reconnectTimer = setTimeout(() => {
|
|
54346
54744
|
reconnectTimer = null;
|
|
54347
54745
|
connect();
|
|
@@ -56224,15 +56622,15 @@ function resolveSelfTuple(promise3) {
|
|
|
56224
56622
|
return Unpromise.proxy(promise3).then(() => [promise3]);
|
|
56225
56623
|
}
|
|
56226
56624
|
function withResolvers() {
|
|
56227
|
-
let
|
|
56625
|
+
let resolve15;
|
|
56228
56626
|
let reject;
|
|
56229
56627
|
const promise3 = new Promise((_resolve, _reject) => {
|
|
56230
|
-
|
|
56628
|
+
resolve15 = _resolve;
|
|
56231
56629
|
reject = _reject;
|
|
56232
56630
|
});
|
|
56233
56631
|
return {
|
|
56234
56632
|
promise: promise3,
|
|
56235
|
-
resolve:
|
|
56633
|
+
resolve: resolve15,
|
|
56236
56634
|
reject
|
|
56237
56635
|
};
|
|
56238
56636
|
}
|
|
@@ -56271,8 +56669,8 @@ function timerResource(ms) {
|
|
|
56271
56669
|
return makeResource({ start() {
|
|
56272
56670
|
if (timer)
|
|
56273
56671
|
throw new Error("Timer already started");
|
|
56274
|
-
const promise3 = new Promise((
|
|
56275
|
-
timer = setTimeout(() =>
|
|
56672
|
+
const promise3 = new Promise((resolve15) => {
|
|
56673
|
+
timer = setTimeout(() => resolve15(disposablePromiseTimerResult), ms);
|
|
56276
56674
|
});
|
|
56277
56675
|
return promise3;
|
|
56278
56676
|
} }, () => {
|
|
@@ -56321,15 +56719,15 @@ function _takeWithGrace() {
|
|
|
56321
56719
|
return _takeWithGrace.apply(this, arguments);
|
|
56322
56720
|
}
|
|
56323
56721
|
function createDeferred() {
|
|
56324
|
-
let
|
|
56722
|
+
let resolve15;
|
|
56325
56723
|
let reject;
|
|
56326
56724
|
const promise3 = new Promise((res, rej) => {
|
|
56327
|
-
|
|
56725
|
+
resolve15 = res;
|
|
56328
56726
|
reject = rej;
|
|
56329
56727
|
});
|
|
56330
56728
|
return {
|
|
56331
56729
|
promise: promise3,
|
|
56332
|
-
resolve:
|
|
56730
|
+
resolve: resolve15,
|
|
56333
56731
|
reject
|
|
56334
56732
|
};
|
|
56335
56733
|
}
|
|
@@ -57305,8 +57703,8 @@ var import_objectSpread2$13, jsonContentTypeHandler, formDataContentTypeHandler,
|
|
|
57305
57703
|
status: "fulfilled",
|
|
57306
57704
|
value
|
|
57307
57705
|
};
|
|
57308
|
-
subscribers === null || subscribers === undefined || subscribers.forEach(({ resolve:
|
|
57309
|
-
|
|
57706
|
+
subscribers === null || subscribers === undefined || subscribers.forEach(({ resolve: resolve15 }) => {
|
|
57707
|
+
resolve15(value);
|
|
57310
57708
|
});
|
|
57311
57709
|
});
|
|
57312
57710
|
if ("catch" in thenReturn)
|
|
@@ -58190,8 +58588,8 @@ function startBridgeServerTRPC(options) {
|
|
|
58190
58588
|
}
|
|
58191
58589
|
const iterable = isObservable(result) ? observableToAsyncIterable(result, abortController.signal) : result;
|
|
58192
58590
|
const iterator = iterable[Symbol.asyncIterator]();
|
|
58193
|
-
const abortPromise = new Promise((
|
|
58194
|
-
abortController.signal.addEventListener("abort", () =>
|
|
58591
|
+
const abortPromise = new Promise((resolve15) => {
|
|
58592
|
+
abortController.signal.addEventListener("abort", () => resolve15("abort"), {
|
|
58195
58593
|
once: true
|
|
58196
58594
|
});
|
|
58197
58595
|
});
|
|
@@ -58553,6 +58951,8 @@ async function startPairingRuntime(options) {
|
|
|
58553
58951
|
}
|
|
58554
58952
|
const relayConnection = connectToRelay(relayUrl, identity2, bridge, {
|
|
58555
58953
|
secure: true,
|
|
58954
|
+
publicRelayUrl: options?.advertisedRelayUrl ?? undefined,
|
|
58955
|
+
fallbackRelayUrls: options?.fallbackRelayUrls,
|
|
58556
58956
|
events: options?.relayEvents
|
|
58557
58957
|
});
|
|
58558
58958
|
await autoStartConfiguredSessions(bridge, config2.sessions);
|
|
@@ -58632,6 +59032,7 @@ function startRelay(port, options = {}) {
|
|
|
58632
59032
|
const roomByBridgeKey = new Map;
|
|
58633
59033
|
const server = Bun.serve({
|
|
58634
59034
|
port,
|
|
59035
|
+
hostname: "0.0.0.0",
|
|
58635
59036
|
...options.tls ? {
|
|
58636
59037
|
tls: {
|
|
58637
59038
|
cert: Bun.file(options.tls.cert),
|
|
@@ -58852,7 +59253,7 @@ var BRIDGE_ABSENCE_GRACE_MS = 30000, ROOM_IDLE_TIMEOUT_MS = 60000;
|
|
|
58852
59253
|
// ../../apps/desktop/src/core/pairing/runtime/relay-runtime.ts
|
|
58853
59254
|
import { execSync as execSync4 } from "child_process";
|
|
58854
59255
|
import { existsSync as existsSync19, mkdirSync as mkdirSync11, readdirSync as readdirSync4 } from "fs";
|
|
58855
|
-
import { homedir as homedir22 } from "os";
|
|
59256
|
+
import { homedir as homedir22, networkInterfaces } from "os";
|
|
58856
59257
|
import { join as join27 } from "path";
|
|
58857
59258
|
function findStoredCerts() {
|
|
58858
59259
|
if (!existsSync19(PAIRING_DIR2)) {
|
|
@@ -58894,24 +59295,42 @@ function readTailscaleStatus2() {
|
|
|
58894
59295
|
return null;
|
|
58895
59296
|
}
|
|
58896
59297
|
}
|
|
58897
|
-
function resolveRelayEndpointForTailscaleStatus(port, tailscale) {
|
|
59298
|
+
function resolveRelayEndpointForTailscaleStatus(port, tailscale, options = {}) {
|
|
58898
59299
|
const backendState = tailscale?.backendState?.trim().toLowerCase() ?? "";
|
|
58899
59300
|
const hostname5 = tailscale?.dnsName ?? null;
|
|
58900
59301
|
const tailscaleRunning = backendState === "running" && tailscale?.online !== false && Boolean(hostname5);
|
|
58901
|
-
const tls =
|
|
58902
|
-
|
|
59302
|
+
const tls = tailscaleRunning ? options.tls !== undefined ? options.tls : resolveTls(hostname5) : null;
|
|
59303
|
+
const scheme = tls ? "wss" : "ws";
|
|
59304
|
+
const connectUrl = `${scheme}://127.0.0.1:${port}`;
|
|
59305
|
+
const localAddress = options.localAddress !== undefined ? normalizedOptionalAddress(options.localAddress) : findLocalNetworkAddress();
|
|
59306
|
+
const localRelayUrl = localAddress ? `${scheme}://${localAddress}:${port}` : null;
|
|
59307
|
+
const tailnetRelayUrl = tailscaleRunning && hostname5 ? `${scheme}://${hostname5}:${port}` : null;
|
|
59308
|
+
const fallbackRelayUrls = tailnetRelayUrl && localRelayUrl ? [tailnetRelayUrl] : [];
|
|
59309
|
+
if (localRelayUrl) {
|
|
59310
|
+
return {
|
|
59311
|
+
relayUrl: localRelayUrl,
|
|
59312
|
+
connectUrl,
|
|
59313
|
+
fallbackRelayUrls,
|
|
59314
|
+
options: tls ? { tls } : {}
|
|
59315
|
+
};
|
|
59316
|
+
}
|
|
59317
|
+
if (tailnetRelayUrl && tls) {
|
|
58903
59318
|
return {
|
|
58904
|
-
relayUrl:
|
|
59319
|
+
relayUrl: tailnetRelayUrl,
|
|
59320
|
+
connectUrl,
|
|
59321
|
+
fallbackRelayUrls: [],
|
|
58905
59322
|
options: { tls }
|
|
58906
59323
|
};
|
|
58907
59324
|
}
|
|
58908
|
-
if (
|
|
59325
|
+
if (tailnetRelayUrl) {
|
|
58909
59326
|
pairingLog.warn("relay", "tailscale is running without TLS; falling back to insecure websocket relay", {
|
|
58910
59327
|
hostname: hostname5,
|
|
58911
59328
|
port
|
|
58912
59329
|
});
|
|
58913
59330
|
return {
|
|
58914
|
-
relayUrl:
|
|
59331
|
+
relayUrl: tailnetRelayUrl,
|
|
59332
|
+
connectUrl,
|
|
59333
|
+
fallbackRelayUrls: [],
|
|
58915
59334
|
options: {}
|
|
58916
59335
|
};
|
|
58917
59336
|
}
|
|
@@ -58924,7 +59343,9 @@ function resolveRelayEndpointForTailscaleStatus(port, tailscale) {
|
|
|
58924
59343
|
});
|
|
58925
59344
|
}
|
|
58926
59345
|
return {
|
|
58927
|
-
relayUrl:
|
|
59346
|
+
relayUrl: connectUrl,
|
|
59347
|
+
connectUrl,
|
|
59348
|
+
fallbackRelayUrls: [],
|
|
58928
59349
|
options: {}
|
|
58929
59350
|
};
|
|
58930
59351
|
}
|
|
@@ -58977,16 +59398,87 @@ function resolveRelayEndpoint(port) {
|
|
|
58977
59398
|
}
|
|
58978
59399
|
function startManagedRelay(port = 7889) {
|
|
58979
59400
|
const endpoint = resolveRelayEndpoint(port);
|
|
58980
|
-
pairingLog.info("relay", "starting managed relay", {
|
|
59401
|
+
pairingLog.info("relay", "starting managed relay", {
|
|
59402
|
+
relay: endpoint.relayUrl,
|
|
59403
|
+
connectUrl: endpoint.connectUrl,
|
|
59404
|
+
fallbackRelayUrls: endpoint.fallbackRelayUrls,
|
|
59405
|
+
port
|
|
59406
|
+
});
|
|
58981
59407
|
const relay = startRelay(port, endpoint.options);
|
|
58982
59408
|
return {
|
|
58983
59409
|
relayUrl: endpoint.relayUrl,
|
|
59410
|
+
connectUrl: endpoint.connectUrl,
|
|
59411
|
+
fallbackRelayUrls: endpoint.fallbackRelayUrls,
|
|
58984
59412
|
stop() {
|
|
58985
59413
|
pairingLog.info("relay", "stopping managed relay", { relay: endpoint.relayUrl, port });
|
|
58986
59414
|
relay.stop();
|
|
58987
59415
|
}
|
|
58988
59416
|
};
|
|
58989
59417
|
}
|
|
59418
|
+
function normalizedOptionalAddress(address) {
|
|
59419
|
+
const trimmed = address?.trim();
|
|
59420
|
+
return trimmed ? trimmed : null;
|
|
59421
|
+
}
|
|
59422
|
+
function findLocalNetworkAddress() {
|
|
59423
|
+
const candidates = [];
|
|
59424
|
+
const interfaces = networkInterfaces();
|
|
59425
|
+
for (const [name, entries] of Object.entries(interfaces)) {
|
|
59426
|
+
for (const entry of entries ?? []) {
|
|
59427
|
+
if (entry.internal || entry.family !== "IPv4") {
|
|
59428
|
+
continue;
|
|
59429
|
+
}
|
|
59430
|
+
if (!isPrivateIPv4(entry.address) || isLinkLocalIPv4(entry.address) || isTailscaleIPv4(entry.address)) {
|
|
59431
|
+
continue;
|
|
59432
|
+
}
|
|
59433
|
+
candidates.push({ name, address: entry.address });
|
|
59434
|
+
}
|
|
59435
|
+
}
|
|
59436
|
+
candidates.sort((left, right) => {
|
|
59437
|
+
const leftScore = localInterfaceScore(left.name);
|
|
59438
|
+
const rightScore = localInterfaceScore(right.name);
|
|
59439
|
+
if (leftScore !== rightScore) {
|
|
59440
|
+
return leftScore - rightScore;
|
|
59441
|
+
}
|
|
59442
|
+
return left.address.localeCompare(right.address);
|
|
59443
|
+
});
|
|
59444
|
+
return candidates[0]?.address ?? null;
|
|
59445
|
+
}
|
|
59446
|
+
function localInterfaceScore(name) {
|
|
59447
|
+
if (/^en\d+$/i.test(name)) {
|
|
59448
|
+
return 0;
|
|
59449
|
+
}
|
|
59450
|
+
if (/^bridge\d*$/i.test(name)) {
|
|
59451
|
+
return 2;
|
|
59452
|
+
}
|
|
59453
|
+
return 1;
|
|
59454
|
+
}
|
|
59455
|
+
function isPrivateIPv4(address) {
|
|
59456
|
+
const octets = parseIPv4(address);
|
|
59457
|
+
if (!octets) {
|
|
59458
|
+
return false;
|
|
59459
|
+
}
|
|
59460
|
+
const [first, second] = octets;
|
|
59461
|
+
return first === 10 || first === 172 && second >= 16 && second <= 31 || first === 192 && second === 168;
|
|
59462
|
+
}
|
|
59463
|
+
function isLinkLocalIPv4(address) {
|
|
59464
|
+
const octets = parseIPv4(address);
|
|
59465
|
+
return Boolean(octets && octets[0] === 169 && octets[1] === 254);
|
|
59466
|
+
}
|
|
59467
|
+
function isTailscaleIPv4(address) {
|
|
59468
|
+
const octets = parseIPv4(address);
|
|
59469
|
+
return Boolean(octets && octets[0] === 100 && octets[1] >= 64 && octets[1] <= 127);
|
|
59470
|
+
}
|
|
59471
|
+
function parseIPv4(address) {
|
|
59472
|
+
const octets = address.split(".");
|
|
59473
|
+
if (octets.length !== 4) {
|
|
59474
|
+
return null;
|
|
59475
|
+
}
|
|
59476
|
+
const numbers = octets.map((octet) => Number(octet));
|
|
59477
|
+
if (numbers.some((value) => !Number.isInteger(value) || value < 0 || value > 255)) {
|
|
59478
|
+
return null;
|
|
59479
|
+
}
|
|
59480
|
+
return numbers;
|
|
59481
|
+
}
|
|
58990
59482
|
var PAIRING_DIR2;
|
|
58991
59483
|
var init_relay_runtime = __esm(() => {
|
|
58992
59484
|
init_log2();
|
|
@@ -59695,12 +60187,19 @@ async function startScoutPairingSession(input) {
|
|
|
59695
60187
|
};
|
|
59696
60188
|
const resolvedRelayUrl = input.forceManagedRelay ? null : input.relayUrl?.trim() || config3.relay;
|
|
59697
60189
|
try {
|
|
59698
|
-
const
|
|
60190
|
+
const managedRelay = resolvedRelayUrl ? null : (() => {
|
|
59699
60191
|
relay = startManagedRelay(config3.port + 1);
|
|
59700
|
-
return relay
|
|
60192
|
+
return relay;
|
|
59701
60193
|
})();
|
|
60194
|
+
const activeRelayUrl = resolvedRelayUrl ?? managedRelay?.relayUrl;
|
|
60195
|
+
const connectRelayUrl = resolvedRelayUrl ?? managedRelay?.connectUrl ?? managedRelay?.relayUrl;
|
|
60196
|
+
if (!activeRelayUrl || !connectRelayUrl) {
|
|
60197
|
+
throw new Error("Scout pairing relay URL is not configured.");
|
|
60198
|
+
}
|
|
59702
60199
|
runtime2 = await startPairingRuntime({
|
|
59703
|
-
relayUrl:
|
|
60200
|
+
relayUrl: connectRelayUrl,
|
|
60201
|
+
advertisedRelayUrl: activeRelayUrl,
|
|
60202
|
+
fallbackRelayUrls: managedRelay?.fallbackRelayUrls,
|
|
59704
60203
|
relayEvents: {
|
|
59705
60204
|
onConnecting() {
|
|
59706
60205
|
emitOrQueue(createStatusEvent("connecting", `Connecting to ${activeRelayUrl}`));
|
|
@@ -59855,8 +60354,8 @@ async function runPairCommand(context, args) {
|
|
|
59855
60354
|
process.on("SIGINT", handleSignal);
|
|
59856
60355
|
process.on("SIGTERM", handleSignal);
|
|
59857
60356
|
try {
|
|
59858
|
-
await new Promise((
|
|
59859
|
-
controller.signal.addEventListener("abort", () =>
|
|
60357
|
+
await new Promise((resolve15) => {
|
|
60358
|
+
controller.signal.addEventListener("abort", () => resolve15(), { once: true });
|
|
59860
60359
|
});
|
|
59861
60360
|
} finally {
|
|
59862
60361
|
process.off("SIGINT", handleSignal);
|
|
@@ -59925,15 +60424,15 @@ __export(exports_server, {
|
|
|
59925
60424
|
runServerCommand: () => runServerCommand,
|
|
59926
60425
|
resolveScoutWebServerEntry: () => resolveScoutWebServerEntry,
|
|
59927
60426
|
resolveScoutControlPlaneWebServerEntry: () => resolveScoutControlPlaneWebServerEntry,
|
|
59928
|
-
resolveBunExecutable: () =>
|
|
60427
|
+
resolveBunExecutable: () => resolveBunExecutable4,
|
|
59929
60428
|
renderServerCommandHelp: () => renderServerCommandHelp,
|
|
59930
60429
|
normalizeServerOpenPath: () => normalizeServerOpenPath
|
|
59931
60430
|
});
|
|
59932
60431
|
import { spawn as spawn5 } from "child_process";
|
|
59933
|
-
import {
|
|
60432
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync12, openSync } from "fs";
|
|
59934
60433
|
import { homedir as homedir23 } from "os";
|
|
59935
|
-
import { dirname as
|
|
59936
|
-
import { fileURLToPath as
|
|
60434
|
+
import { dirname as dirname15, join as join28, resolve as resolve15 } from "path";
|
|
60435
|
+
import { fileURLToPath as fileURLToPath10 } from "url";
|
|
59937
60436
|
function renderServerCommandHelp() {
|
|
59938
60437
|
return [
|
|
59939
60438
|
"scout server \u2014 Scout web UI (Bun runtime)",
|
|
@@ -59948,11 +60447,11 @@ function renderServerCommandHelp() {
|
|
|
59948
60447
|
" open Open the Scout web UI (starts server on demand if needed).",
|
|
59949
60448
|
"",
|
|
59950
60449
|
"Options:",
|
|
59951
|
-
" --port <n> Listen port (default 3200;
|
|
60450
|
+
" --port <n> Listen port (default 3200; optional override OPENSCOUT_WEB_PORT)",
|
|
59952
60451
|
" --static Serve built UI from disk",
|
|
59953
|
-
" --static-root DIR Static client root (
|
|
59954
|
-
" --vite-url URL Dev proxy target for non-API routes (
|
|
59955
|
-
" --cwd DIR Workspace / setup root (
|
|
60452
|
+
" --static-root DIR Static client root (optional override OPENSCOUT_WEB_STATIC_ROOT)",
|
|
60453
|
+
" --vite-url URL Dev proxy target for non-API routes (optional override OPENSCOUT_WEB_VITE_URL)",
|
|
60454
|
+
" --cwd DIR Workspace / setup root (optional override OPENSCOUT_SETUP_CWD)",
|
|
59956
60455
|
" --path PATH Browser path for `open` (default /)",
|
|
59957
60456
|
"",
|
|
59958
60457
|
"Requires `bun` on PATH."
|
|
@@ -59963,19 +60462,21 @@ function resolveScoutWebServerEntry() {
|
|
|
59963
60462
|
return resolveScoutControlPlaneWebServerEntry();
|
|
59964
60463
|
}
|
|
59965
60464
|
function resolveScoutControlPlaneWebServerEntry() {
|
|
59966
|
-
const
|
|
59967
|
-
|
|
59968
|
-
if (existsSync20(bundled)) {
|
|
60465
|
+
const bundled = resolveBundledEntrypoint(import.meta.url, "scout-control-plane-web.mjs");
|
|
60466
|
+
if (bundled) {
|
|
59969
60467
|
return bundled;
|
|
59970
60468
|
}
|
|
59971
|
-
const
|
|
59972
|
-
|
|
60469
|
+
const repoRoot = resolveOpenScoutRepoRoot({
|
|
60470
|
+
startDirectories: [
|
|
60471
|
+
process.env.OPENSCOUT_SETUP_CWD,
|
|
60472
|
+
process.cwd(),
|
|
60473
|
+
dirname15(fileURLToPath10(import.meta.url))
|
|
60474
|
+
]
|
|
60475
|
+
});
|
|
60476
|
+
const source = resolveRepoEntrypoint(repoRoot, "packages/web/server/index.ts");
|
|
60477
|
+
if (source) {
|
|
59973
60478
|
return source;
|
|
59974
60479
|
}
|
|
59975
|
-
const legacySource = fileURLToPath9(new URL("../../server/control-plane-index.ts", import.meta.url).href);
|
|
59976
|
-
if (existsSync20(legacySource)) {
|
|
59977
|
-
return legacySource;
|
|
59978
|
-
}
|
|
59979
60480
|
throw new ScoutCliError("Could not find Scout web server entry. Rebuild @openscout/scout or run from the OpenScout repository.");
|
|
59980
60481
|
}
|
|
59981
60482
|
function parseServerFlags(args) {
|
|
@@ -60047,46 +60548,17 @@ function parseServerFlags(args) {
|
|
|
60047
60548
|
return { env, openPath };
|
|
60048
60549
|
}
|
|
60049
60550
|
function resolveBundledStaticClientRoot(entry, _mode) {
|
|
60050
|
-
const entryDir =
|
|
60551
|
+
const entryDir = dirname15(entry);
|
|
60051
60552
|
const clientDirectory = join28(entryDir, "client");
|
|
60052
60553
|
const indexPath = join28(clientDirectory, "index.html");
|
|
60053
60554
|
return existsSync20(indexPath) ? clientDirectory : null;
|
|
60054
60555
|
}
|
|
60055
|
-
function
|
|
60056
|
-
|
|
60057
|
-
|
|
60058
|
-
|
|
60059
|
-
try {
|
|
60060
|
-
accessSync2(filePath, constants4.X_OK);
|
|
60061
|
-
return true;
|
|
60062
|
-
} catch {
|
|
60063
|
-
return false;
|
|
60064
|
-
}
|
|
60065
|
-
}
|
|
60066
|
-
function resolveBunExecutable3(env) {
|
|
60067
|
-
const explicitPaths = [
|
|
60068
|
-
env.SCOUT_BUN_BIN,
|
|
60069
|
-
env.OPENSCOUT_BUN_BIN,
|
|
60070
|
-
env.BUN_BIN
|
|
60071
|
-
].filter((candidate) => Boolean(candidate?.trim()));
|
|
60072
|
-
for (const candidate of explicitPaths) {
|
|
60073
|
-
if (isExecutable4(candidate)) {
|
|
60074
|
-
return candidate;
|
|
60075
|
-
}
|
|
60076
|
-
}
|
|
60077
|
-
const pathEntries = (env.PATH ?? "").split(":").filter(Boolean);
|
|
60078
|
-
const commonDirectories = [
|
|
60079
|
-
join28(homedir23(), ".bun", "bin"),
|
|
60080
|
-
"/opt/homebrew/bin",
|
|
60081
|
-
"/usr/local/bin"
|
|
60082
|
-
];
|
|
60083
|
-
for (const directory of [...pathEntries, ...commonDirectories]) {
|
|
60084
|
-
const candidate = join28(directory.replace(/^~(?=$|\/)/, homedir23()), "bun");
|
|
60085
|
-
if (isExecutable4(candidate)) {
|
|
60086
|
-
return candidate;
|
|
60087
|
-
}
|
|
60556
|
+
function resolveBunExecutable4(env) {
|
|
60557
|
+
const bun = resolveBunExecutable2(env);
|
|
60558
|
+
if (bun) {
|
|
60559
|
+
return bun.path;
|
|
60088
60560
|
}
|
|
60089
|
-
|
|
60561
|
+
throw new ScoutCliError("Unable to locate Bun. Install Bun (https://bun.sh) or set OPENSCOUT_BUN_BIN.");
|
|
60090
60562
|
}
|
|
60091
60563
|
function buildMergedServerEnv(entry, mode, flagEnv) {
|
|
60092
60564
|
const bundledStaticClientRoot = resolveBundledStaticClientRoot(entry, mode);
|
|
@@ -60156,13 +60628,13 @@ function resolveServerPort(env) {
|
|
|
60156
60628
|
}
|
|
60157
60629
|
return port;
|
|
60158
60630
|
}
|
|
60159
|
-
|
|
60160
|
-
if (fromFile)
|
|
60161
|
-
return fromFile;
|
|
60162
|
-
return 3200;
|
|
60631
|
+
return resolveWebPort();
|
|
60163
60632
|
}
|
|
60164
60633
|
function resolveExpectedCurrentDirectory(env) {
|
|
60165
|
-
return
|
|
60634
|
+
return resolveOpenScoutSetupContextRoot({
|
|
60635
|
+
env,
|
|
60636
|
+
fallbackDirectory: process.cwd()
|
|
60637
|
+
});
|
|
60166
60638
|
}
|
|
60167
60639
|
function renderModeLabel(mode) {
|
|
60168
60640
|
return "Scout web";
|
|
@@ -60259,12 +60731,19 @@ async function openBrowser(url2) {
|
|
|
60259
60731
|
});
|
|
60260
60732
|
});
|
|
60261
60733
|
}
|
|
60734
|
+
function resolveScoutWebServerLogPath() {
|
|
60735
|
+
const dir = join28(homedir23(), ".scout", "logs");
|
|
60736
|
+
mkdirSync12(dir, { recursive: true });
|
|
60737
|
+
return join28(dir, "web-server.log");
|
|
60738
|
+
}
|
|
60262
60739
|
async function spawnDetachedServer(entry, env) {
|
|
60263
|
-
const bunExecutable =
|
|
60740
|
+
const bunExecutable = resolveBunExecutable4(env);
|
|
60741
|
+
const logPath = resolveScoutWebServerLogPath();
|
|
60742
|
+
const logFd = openSync(logPath, "a");
|
|
60264
60743
|
await new Promise((resolvePromise, rejectPromise) => {
|
|
60265
60744
|
const child = spawn5(bunExecutable, ["run", entry], {
|
|
60266
60745
|
detached: true,
|
|
60267
|
-
stdio: "ignore",
|
|
60746
|
+
stdio: ["ignore", logFd, logFd],
|
|
60268
60747
|
env,
|
|
60269
60748
|
windowsHide: true
|
|
60270
60749
|
});
|
|
@@ -60286,7 +60765,7 @@ async function waitForScoutServer(port, mode, expectedCurrentDirectory) {
|
|
|
60286
60765
|
while (Date.now() < deadline) {
|
|
60287
60766
|
const probe = await probeScoutServer(port);
|
|
60288
60767
|
if (probe.status === "healthy") {
|
|
60289
|
-
const actualCurrentDirectory =
|
|
60768
|
+
const actualCurrentDirectory = resolve15(probe.health.currentDirectory);
|
|
60290
60769
|
if (!isCurrentScoutWebSurface(probe.health.surface)) {
|
|
60291
60770
|
throw new ScoutCliError(`port ${port} is serving Scout ${renderSurfaceLabel(probe.health.surface)}, not ${renderModeLabel(mode)}.`);
|
|
60292
60771
|
}
|
|
@@ -60300,7 +60779,7 @@ async function waitForScoutServer(port, mode, expectedCurrentDirectory) {
|
|
|
60300
60779
|
}
|
|
60301
60780
|
await new Promise((resolvePromise) => setTimeout(resolvePromise, 250));
|
|
60302
60781
|
}
|
|
60303
|
-
throw new ScoutCliError(`timed out waiting for ${renderModeLabel(mode)} on port ${port}`);
|
|
60782
|
+
throw new ScoutCliError(`timed out waiting for ${renderModeLabel(mode)} on port ${port}; check ${resolveScoutWebServerLogPath()} for the child process output`);
|
|
60304
60783
|
}
|
|
60305
60784
|
async function openScoutServer(options) {
|
|
60306
60785
|
const port = resolveServerPort(options.env);
|
|
@@ -60308,7 +60787,7 @@ async function openScoutServer(options) {
|
|
|
60308
60787
|
const browserUrl = new URL(normalizeServerOpenPath(options.openPath), `http://127.0.0.1:${port}`).toString();
|
|
60309
60788
|
const probe = await probeScoutServer(port);
|
|
60310
60789
|
if (probe.status === "healthy") {
|
|
60311
|
-
const actualCurrentDirectory =
|
|
60790
|
+
const actualCurrentDirectory = resolve15(probe.health.currentDirectory);
|
|
60312
60791
|
if (!isCurrentScoutWebSurface(probe.health.surface)) {
|
|
60313
60792
|
throw new ScoutCliError(`port ${port} is already serving Scout ${renderSurfaceLabel(probe.health.surface)}, not ${renderModeLabel(options.mode)}.`);
|
|
60314
60793
|
}
|
|
@@ -60354,7 +60833,7 @@ async function runServerCommand(context, args) {
|
|
|
60354
60833
|
context.output.writeValue(result, renderServerOpenResult);
|
|
60355
60834
|
return;
|
|
60356
60835
|
}
|
|
60357
|
-
const bunExecutable =
|
|
60836
|
+
const bunExecutable = resolveBunExecutable4(mergedEnv);
|
|
60358
60837
|
await new Promise((resolvePromise, rejectPromise) => {
|
|
60359
60838
|
const child = spawn5(bunExecutable, ["run", selection.entry], {
|
|
60360
60839
|
stdio: "inherit",
|
|
@@ -60387,6 +60866,8 @@ async function runServerCommand(context, args) {
|
|
|
60387
60866
|
var SERVER_OPEN_TIMEOUT_MS = 15000, SERVER_HEALTH_TIMEOUT_MS = 1500;
|
|
60388
60867
|
var init_server4 = __esm(() => {
|
|
60389
60868
|
init_local_config();
|
|
60869
|
+
init_tool_resolution();
|
|
60870
|
+
init_setup();
|
|
60390
60871
|
init_errors();
|
|
60391
60872
|
});
|
|
60392
60873
|
|
|
@@ -60417,9 +60898,10 @@ async function runSpeakCommand(context, args) {
|
|
|
60417
60898
|
const senderId = await resolveScoutSenderId(options.agentName, currentDirectory, context.env);
|
|
60418
60899
|
const config3 = await loadScoutRelayConfig();
|
|
60419
60900
|
const voice = getScoutVoiceForChannel(config3, "voice");
|
|
60901
|
+
const body = await resolveMessageBody(options);
|
|
60420
60902
|
await acquireScoutOnAir(senderId);
|
|
60421
60903
|
try {
|
|
60422
|
-
const clean3 = stripScoutAgentSelectorLabels(
|
|
60904
|
+
const clean3 = stripScoutAgentSelectorLabels(body);
|
|
60423
60905
|
if (clean3) {
|
|
60424
60906
|
await speakScoutText(clean3, voice);
|
|
60425
60907
|
}
|
|
@@ -60428,7 +60910,7 @@ async function runSpeakCommand(context, args) {
|
|
|
60428
60910
|
}
|
|
60429
60911
|
const result = await sendScoutMessage({
|
|
60430
60912
|
senderId,
|
|
60431
|
-
body
|
|
60913
|
+
body,
|
|
60432
60914
|
channel: "voice",
|
|
60433
60915
|
shouldSpeak: true,
|
|
60434
60916
|
executionHarness: parseScoutHarness(options.harness),
|
|
@@ -60438,16 +60920,17 @@ async function runSpeakCommand(context, args) {
|
|
|
60438
60920
|
throw new Error("broker is not reachable");
|
|
60439
60921
|
}
|
|
60440
60922
|
if (result.unresolvedTargets.length > 0) {
|
|
60441
|
-
throw new Error(formatScoutSendRoutingError(result
|
|
60923
|
+
throw new Error(formatScoutSendRoutingError(result));
|
|
60442
60924
|
}
|
|
60443
60925
|
context.output.writeValue({
|
|
60444
|
-
message:
|
|
60926
|
+
message: body,
|
|
60445
60927
|
invokedTargets: result.invokedTargets,
|
|
60446
60928
|
unresolvedTargets: result.unresolvedTargets
|
|
60447
60929
|
}, renderScoutMessagePostResult);
|
|
60448
60930
|
}
|
|
60449
60931
|
var init_speak = __esm(async () => {
|
|
60450
60932
|
init_context();
|
|
60933
|
+
init_input_file();
|
|
60451
60934
|
init_options();
|
|
60452
60935
|
init_broker();
|
|
60453
60936
|
await __promiseAll([
|
|
@@ -60505,8 +60988,8 @@ import { EventEmitter } from "events";
|
|
|
60505
60988
|
import { Buffer as Buffer2 } from "buffer";
|
|
60506
60989
|
import { Buffer as Buffer3 } from "buffer";
|
|
60507
60990
|
import { EventEmitter as EventEmitter2 } from "events";
|
|
60508
|
-
import { resolve as
|
|
60509
|
-
import { fileURLToPath as
|
|
60991
|
+
import { resolve as resolve16, dirname as dirname16 } from "path";
|
|
60992
|
+
import { fileURLToPath as fileURLToPath11 } from "url";
|
|
60510
60993
|
import { resolve as resolve22, isAbsolute as isAbsolute5, parse as parse7 } from "path";
|
|
60511
60994
|
import { existsSync as existsSync21 } from "fs";
|
|
60512
60995
|
import { basename as basename11, join as join29 } from "path";
|
|
@@ -60516,7 +60999,7 @@ import { EventEmitter as EventEmitter3 } from "events";
|
|
|
60516
60999
|
import path22 from "path";
|
|
60517
61000
|
import { readFile as readFile22, writeFile as writeFile22, mkdir as mkdir22 } from "fs/promises";
|
|
60518
61001
|
import * as path4 from "path";
|
|
60519
|
-
import { mkdir as mkdir9, readFile as
|
|
61002
|
+
import { mkdir as mkdir9, readFile as readFile11, writeFile as writeFile8 } from "fs/promises";
|
|
60520
61003
|
import * as path3 from "path";
|
|
60521
61004
|
import { readdir as readdir3 } from "fs/promises";
|
|
60522
61005
|
import { dlopen, toArrayBuffer as toArrayBuffer4, JSCallback, ptr as ptr4 } from "bun:ffi";
|
|
@@ -63641,13 +64124,13 @@ class DebounceController {
|
|
|
63641
64124
|
}
|
|
63642
64125
|
debounce(id, ms, fn) {
|
|
63643
64126
|
const scopeMap = TIMERS_MAP.get(this.scopeId);
|
|
63644
|
-
return new Promise((
|
|
64127
|
+
return new Promise((resolve18, reject) => {
|
|
63645
64128
|
if (scopeMap.has(id)) {
|
|
63646
64129
|
clearTimeout(scopeMap.get(id));
|
|
63647
64130
|
}
|
|
63648
64131
|
const timerId = setTimeout(() => {
|
|
63649
64132
|
try {
|
|
63650
|
-
|
|
64133
|
+
resolve18(fn());
|
|
63651
64134
|
} catch (error48) {
|
|
63652
64135
|
reject(error48);
|
|
63653
64136
|
}
|
|
@@ -63737,25 +64220,25 @@ function getParsers() {
|
|
|
63737
64220
|
filetype: "javascript",
|
|
63738
64221
|
aliases: ["javascriptreact"],
|
|
63739
64222
|
queries: {
|
|
63740
|
-
highlights: [
|
|
64223
|
+
highlights: [resolve16(dirname16(fileURLToPath11(import.meta.url)), highlights_default)]
|
|
63741
64224
|
},
|
|
63742
|
-
wasm:
|
|
64225
|
+
wasm: resolve16(dirname16(fileURLToPath11(import.meta.url)), tree_sitter_javascript_default)
|
|
63743
64226
|
},
|
|
63744
64227
|
{
|
|
63745
64228
|
filetype: "typescript",
|
|
63746
64229
|
aliases: ["typescriptreact"],
|
|
63747
64230
|
queries: {
|
|
63748
|
-
highlights: [
|
|
64231
|
+
highlights: [resolve16(dirname16(fileURLToPath11(import.meta.url)), highlights_default2)]
|
|
63749
64232
|
},
|
|
63750
|
-
wasm:
|
|
64233
|
+
wasm: resolve16(dirname16(fileURLToPath11(import.meta.url)), tree_sitter_typescript_default)
|
|
63751
64234
|
},
|
|
63752
64235
|
{
|
|
63753
64236
|
filetype: "markdown",
|
|
63754
64237
|
queries: {
|
|
63755
|
-
highlights: [
|
|
63756
|
-
injections: [
|
|
64238
|
+
highlights: [resolve16(dirname16(fileURLToPath11(import.meta.url)), highlights_default3)],
|
|
64239
|
+
injections: [resolve16(dirname16(fileURLToPath11(import.meta.url)), injections_default)]
|
|
63757
64240
|
},
|
|
63758
|
-
wasm:
|
|
64241
|
+
wasm: resolve16(dirname16(fileURLToPath11(import.meta.url)), tree_sitter_markdown_default),
|
|
63759
64242
|
injectionMapping: {
|
|
63760
64243
|
nodeTypes: {
|
|
63761
64244
|
inline: "markdown_inline",
|
|
@@ -63778,16 +64261,16 @@ function getParsers() {
|
|
|
63778
64261
|
{
|
|
63779
64262
|
filetype: "markdown_inline",
|
|
63780
64263
|
queries: {
|
|
63781
|
-
highlights: [
|
|
64264
|
+
highlights: [resolve16(dirname16(fileURLToPath11(import.meta.url)), highlights_default4)]
|
|
63782
64265
|
},
|
|
63783
|
-
wasm:
|
|
64266
|
+
wasm: resolve16(dirname16(fileURLToPath11(import.meta.url)), tree_sitter_markdown_inline_default)
|
|
63784
64267
|
},
|
|
63785
64268
|
{
|
|
63786
64269
|
filetype: "zig",
|
|
63787
64270
|
queries: {
|
|
63788
|
-
highlights: [
|
|
64271
|
+
highlights: [resolve16(dirname16(fileURLToPath11(import.meta.url)), highlights_default5)]
|
|
63789
64272
|
},
|
|
63790
|
-
wasm:
|
|
64273
|
+
wasm: resolve16(dirname16(fileURLToPath11(import.meta.url)), tree_sitter_zig_default)
|
|
63791
64274
|
}
|
|
63792
64275
|
];
|
|
63793
64276
|
}
|
|
@@ -63929,7 +64412,7 @@ class DownloadUtils {
|
|
|
63929
64412
|
const cacheFile = path3.join(cacheDir, cacheSubdir, cacheFileName);
|
|
63930
64413
|
await mkdir9(path3.dirname(cacheFile), { recursive: true });
|
|
63931
64414
|
try {
|
|
63932
|
-
const cachedContent = await
|
|
64415
|
+
const cachedContent = await readFile11(cacheFile);
|
|
63933
64416
|
if (cachedContent.byteLength > 0) {
|
|
63934
64417
|
console.log(`Loaded from cache: ${cacheFile} (${source})`);
|
|
63935
64418
|
return { content: cachedContent, filePath: cacheFile };
|
|
@@ -63955,7 +64438,7 @@ class DownloadUtils {
|
|
|
63955
64438
|
} else {
|
|
63956
64439
|
try {
|
|
63957
64440
|
console.log(`Loading from local path: ${source}`);
|
|
63958
|
-
const content = await
|
|
64441
|
+
const content = await readFile11(source);
|
|
63959
64442
|
return { content, filePath: source };
|
|
63960
64443
|
} catch (error48) {
|
|
63961
64444
|
return { error: `Error loading from local path ${source}: ${error48}` };
|
|
@@ -63982,7 +64465,7 @@ class DownloadUtils {
|
|
|
63982
64465
|
} else {
|
|
63983
64466
|
try {
|
|
63984
64467
|
console.log(`Copying from local path: ${source}`);
|
|
63985
|
-
const content = await
|
|
64468
|
+
const content = await readFile11(source);
|
|
63986
64469
|
await writeFile8(targetPath, Buffer.from(content));
|
|
63987
64470
|
return { content, filePath: targetPath };
|
|
63988
64471
|
} catch (error48) {
|
|
@@ -93023,14 +93506,14 @@ See https://react.dev/link/invalid-hook-call for tips about how to debug and fix
|
|
|
93023
93506
|
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. ");
|
|
93024
93507
|
actScopeDepth = prevActScopeDepth;
|
|
93025
93508
|
}
|
|
93026
|
-
function recursivelyFlushAsyncActWork(returnValue,
|
|
93509
|
+
function recursivelyFlushAsyncActWork(returnValue, resolve18, reject) {
|
|
93027
93510
|
var queue = ReactSharedInternals.actQueue;
|
|
93028
93511
|
if (queue !== null)
|
|
93029
93512
|
if (queue.length !== 0)
|
|
93030
93513
|
try {
|
|
93031
93514
|
flushActQueue(queue);
|
|
93032
93515
|
enqueueTask(function() {
|
|
93033
|
-
return recursivelyFlushAsyncActWork(returnValue,
|
|
93516
|
+
return recursivelyFlushAsyncActWork(returnValue, resolve18, reject);
|
|
93034
93517
|
});
|
|
93035
93518
|
return;
|
|
93036
93519
|
} catch (error48) {
|
|
@@ -93038,7 +93521,7 @@ See https://react.dev/link/invalid-hook-call for tips about how to debug and fix
|
|
|
93038
93521
|
}
|
|
93039
93522
|
else
|
|
93040
93523
|
ReactSharedInternals.actQueue = null;
|
|
93041
|
-
0 < ReactSharedInternals.thrownErrors.length ? (queue = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, reject(queue)) :
|
|
93524
|
+
0 < ReactSharedInternals.thrownErrors.length ? (queue = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, reject(queue)) : resolve18(returnValue);
|
|
93042
93525
|
}
|
|
93043
93526
|
function flushActQueue(queue) {
|
|
93044
93527
|
if (!isFlushing) {
|
|
@@ -93214,14 +93697,14 @@ See https://react.dev/link/invalid-hook-call for tips about how to debug and fix
|
|
|
93214
93697
|
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 () => ...);"));
|
|
93215
93698
|
});
|
|
93216
93699
|
return {
|
|
93217
|
-
then: function(
|
|
93700
|
+
then: function(resolve18, reject) {
|
|
93218
93701
|
didAwaitActCall = true;
|
|
93219
93702
|
thenable.then(function(returnValue) {
|
|
93220
93703
|
popActScope(prevActQueue, prevActScopeDepth);
|
|
93221
93704
|
if (prevActScopeDepth === 0) {
|
|
93222
93705
|
try {
|
|
93223
93706
|
flushActQueue(queue), enqueueTask(function() {
|
|
93224
|
-
return recursivelyFlushAsyncActWork(returnValue,
|
|
93707
|
+
return recursivelyFlushAsyncActWork(returnValue, resolve18, reject);
|
|
93225
93708
|
});
|
|
93226
93709
|
} catch (error$0) {
|
|
93227
93710
|
ReactSharedInternals.thrownErrors.push(error$0);
|
|
@@ -93232,7 +93715,7 @@ See https://react.dev/link/invalid-hook-call for tips about how to debug and fix
|
|
|
93232
93715
|
reject(_thrownError);
|
|
93233
93716
|
}
|
|
93234
93717
|
} else
|
|
93235
|
-
|
|
93718
|
+
resolve18(returnValue);
|
|
93236
93719
|
}, function(error48) {
|
|
93237
93720
|
popActScope(prevActQueue, prevActScopeDepth);
|
|
93238
93721
|
0 < ReactSharedInternals.thrownErrors.length ? (error48 = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, reject(error48)) : reject(error48);
|
|
@@ -93248,11 +93731,11 @@ See https://react.dev/link/invalid-hook-call for tips about how to debug and fix
|
|
|
93248
93731
|
if (0 < ReactSharedInternals.thrownErrors.length)
|
|
93249
93732
|
throw callback = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, callback;
|
|
93250
93733
|
return {
|
|
93251
|
-
then: function(
|
|
93734
|
+
then: function(resolve18, reject) {
|
|
93252
93735
|
didAwaitActCall = true;
|
|
93253
93736
|
prevActScopeDepth === 0 ? (ReactSharedInternals.actQueue = queue, enqueueTask(function() {
|
|
93254
|
-
return recursivelyFlushAsyncActWork(returnValue$jscomp$0,
|
|
93255
|
-
})) :
|
|
93737
|
+
return recursivelyFlushAsyncActWork(returnValue$jscomp$0, resolve18, reject);
|
|
93738
|
+
})) : resolve18(returnValue$jscomp$0);
|
|
93256
93739
|
}
|
|
93257
93740
|
};
|
|
93258
93741
|
};
|
|
@@ -95733,8 +96216,8 @@ It can also happen if the client has a browser extension installed which messes
|
|
|
95733
96216
|
currentEntangledActionThenable = {
|
|
95734
96217
|
status: "pending",
|
|
95735
96218
|
value: undefined,
|
|
95736
|
-
then: function(
|
|
95737
|
-
entangledListeners.push(
|
|
96219
|
+
then: function(resolve18) {
|
|
96220
|
+
entangledListeners.push(resolve18);
|
|
95738
96221
|
}
|
|
95739
96222
|
};
|
|
95740
96223
|
}
|
|
@@ -95758,8 +96241,8 @@ It can also happen if the client has a browser extension installed which messes
|
|
|
95758
96241
|
status: "pending",
|
|
95759
96242
|
value: null,
|
|
95760
96243
|
reason: null,
|
|
95761
|
-
then: function(
|
|
95762
|
-
listeners.push(
|
|
96244
|
+
then: function(resolve18) {
|
|
96245
|
+
listeners.push(resolve18);
|
|
95763
96246
|
}
|
|
95764
96247
|
};
|
|
95765
96248
|
thenable.then(function() {
|
|
@@ -121741,14 +122224,14 @@ async function runScoutMonitorApp(options) {
|
|
|
121741
122224
|
}
|
|
121742
122225
|
const renderer = await createCliRenderer();
|
|
121743
122226
|
let closed = false;
|
|
121744
|
-
await new Promise((
|
|
122227
|
+
await new Promise((resolve18) => {
|
|
121745
122228
|
const close = () => {
|
|
121746
122229
|
if (closed) {
|
|
121747
122230
|
return;
|
|
121748
122231
|
}
|
|
121749
122232
|
closed = true;
|
|
121750
122233
|
renderer.destroy();
|
|
121751
|
-
|
|
122234
|
+
resolve18();
|
|
121752
122235
|
};
|
|
121753
122236
|
createRoot(renderer).render(/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ScoutMonitorApp, {
|
|
121754
122237
|
currentDirectory: options.currentDirectory,
|
|
@@ -121797,7 +122280,7 @@ __export(exports_up, {
|
|
|
121797
122280
|
runUpCommand: () => runUpCommand
|
|
121798
122281
|
});
|
|
121799
122282
|
import { existsSync as existsSync23 } from "fs";
|
|
121800
|
-
import { resolve as
|
|
122283
|
+
import { resolve as resolve18 } from "path";
|
|
121801
122284
|
function looksLikePath(value) {
|
|
121802
122285
|
return value.includes("/") || value.startsWith(".") || value.startsWith("~");
|
|
121803
122286
|
}
|
|
@@ -121859,14 +122342,19 @@ async function runUpCommand(context, args) {
|
|
|
121859
122342
|
throw new ScoutCliError("usage: scout up <name|path> [--name <alias>] [--harness <claude|codex>] [--model <model>]");
|
|
121860
122343
|
}
|
|
121861
122344
|
let projectPath;
|
|
121862
|
-
if (looksLikePath(target) || existsSync23(
|
|
121863
|
-
projectPath =
|
|
122345
|
+
if (looksLikePath(target) || existsSync23(resolve18(target))) {
|
|
122346
|
+
projectPath = resolve18(target);
|
|
121864
122347
|
} else {
|
|
121865
122348
|
const resolved = await resolveLocalAgentByName(target);
|
|
121866
122349
|
if (!resolved) {
|
|
121867
|
-
|
|
122350
|
+
const projectMatch = await resolveLocalAgentByName(target, { matchProjectName: true });
|
|
122351
|
+
if (projectMatch) {
|
|
122352
|
+
throw new ScoutCliError(`unknown agent "${target}" \u2014 that matches project "${projectMatch.projectRoot}", ` + `but the registered agent is "${projectMatch.agentId}". ` + `Use \`scout up ${projectMatch.agentId}\` or \`scout up "${projectMatch.projectRoot}"\`.`);
|
|
122353
|
+
}
|
|
122354
|
+
throw new ScoutCliError(`unknown agent "${target}" \u2014 not a registered agent name or valid path`);
|
|
121868
122355
|
}
|
|
121869
122356
|
projectPath = resolved.projectRoot;
|
|
122357
|
+
agentName ??= resolved.definitionId;
|
|
121870
122358
|
}
|
|
121871
122359
|
const agent = await upScoutAgent({
|
|
121872
122360
|
projectPath,
|
|
@@ -121980,7 +122468,7 @@ var init_whoami = __esm(async () => {
|
|
|
121980
122468
|
});
|
|
121981
122469
|
|
|
121982
122470
|
// ../../apps/desktop/src/cli/main.ts
|
|
121983
|
-
import { existsSync as existsSync25, readFileSync as readFileSync15, writeFileSync as writeFileSync9, statSync as statSync5, mkdirSync as
|
|
122471
|
+
import { existsSync as existsSync25, readFileSync as readFileSync15, writeFileSync as writeFileSync9, statSync as statSync5, mkdirSync as mkdirSync13 } from "fs";
|
|
121984
122472
|
import { join as join32 } from "path";
|
|
121985
122473
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
121986
122474
|
import { homedir as homedir24 } from "os";
|
|
@@ -122147,12 +122635,12 @@ function renderScoutHelp(version2 = "0.2.18") {
|
|
|
122147
122635
|
"Global flags:",
|
|
122148
122636
|
' --json Structured JSON (doctor: NDJSON stream; last object has phase "complete")',
|
|
122149
122637
|
"",
|
|
122150
|
-
"
|
|
122151
|
-
|
|
122152
|
-
|
|
122153
|
-
" scout
|
|
122638
|
+
"Fast path:",
|
|
122639
|
+
' scout send "@hudson ready for review" # tell / update in a DM',
|
|
122640
|
+
' scout ask --to hudson "review the parser" # owned work / reply in a DM',
|
|
122641
|
+
" scout ask --to hudson --prompt-file ./handoff.md",
|
|
122154
122642
|
"",
|
|
122155
|
-
"
|
|
122643
|
+
"Orientation (only when route or sender is unclear):",
|
|
122156
122644
|
" scout whoami",
|
|
122157
122645
|
" scout who",
|
|
122158
122646
|
" scout latest",
|
|
@@ -122165,9 +122653,21 @@ function renderScoutHelp(version2 = "0.2.18") {
|
|
|
122165
122653
|
" scout card create # fresh reply-ready return address",
|
|
122166
122654
|
' scout broadcast "deploying in 15m" # explicit shared broadcast',
|
|
122167
122655
|
"",
|
|
122656
|
+
"Implicit ask shortcut:",
|
|
122657
|
+
" scout @agent your request",
|
|
122658
|
+
" scout @agent --prompt-file ./handoff.md",
|
|
122659
|
+
" scout hey @agent can you review this?",
|
|
122660
|
+
" scout @agent.harness:codex use the Codex-backed one",
|
|
122661
|
+
"",
|
|
122662
|
+
"File-backed input:",
|
|
122663
|
+
" ask uses --prompt-file for the primary work prompt",
|
|
122664
|
+
" send/broadcast/speak use --message-file for the message body",
|
|
122665
|
+
" --body-file is accepted as the shared alias",
|
|
122666
|
+
"",
|
|
122168
122667
|
"One-to-one delegation:",
|
|
122169
122668
|
' scout ask --to hudson "review the parser" # DM by default',
|
|
122170
122669
|
' scout ask --as premotion.master.mini --to hudson "build the editor"',
|
|
122670
|
+
" scout ask --to hudson --prompt-file ./handoff.md",
|
|
122171
122671
|
"",
|
|
122172
122672
|
"Routing:",
|
|
122173
122673
|
' scout send "@hudson ready for review" # one target -> DM',
|
|
@@ -122195,6 +122695,16 @@ function renderScoutHelp(version2 = "0.2.18") {
|
|
|
122195
122695
|
|
|
122196
122696
|
// ../../apps/desktop/src/cli/main.ts
|
|
122197
122697
|
init_options();
|
|
122698
|
+
|
|
122699
|
+
// ../../apps/desktop/src/cli/uptodate.ts
|
|
122700
|
+
function normalizeCliBinaryMtimeMs(value) {
|
|
122701
|
+
return Math.floor(value);
|
|
122702
|
+
}
|
|
122703
|
+
function shouldRestartBrokerForCliMtime(currentMtimeMs, persistedMtimeMs) {
|
|
122704
|
+
return normalizeCliBinaryMtimeMs(currentMtimeMs) > normalizeCliBinaryMtimeMs(persistedMtimeMs);
|
|
122705
|
+
}
|
|
122706
|
+
|
|
122707
|
+
// ../../apps/desktop/src/cli/main.ts
|
|
122198
122708
|
init_product();
|
|
122199
122709
|
async function main3() {
|
|
122200
122710
|
const input = parseScoutArgv(process.argv.slice(2));
|
|
@@ -122251,22 +122761,22 @@ function getScoutBinPath() {
|
|
|
122251
122761
|
}
|
|
122252
122762
|
async function ensureBrokerUptodate() {
|
|
122253
122763
|
try {
|
|
122254
|
-
const mtime = statSync5(getScoutBinPath()).mtimeMs;
|
|
122764
|
+
const mtime = normalizeCliBinaryMtimeMs(statSync5(getScoutBinPath()).mtimeMs);
|
|
122255
122765
|
const checkpointDir = join32(homedir24(), ".scout");
|
|
122256
122766
|
const mtimePath = join32(checkpointDir, "cli-mtime");
|
|
122257
122767
|
const lastMtime = existsSync25(mtimePath) ? Number(readFileSync15(mtimePath, "utf8").trim()) : 0;
|
|
122258
|
-
if (mtime
|
|
122768
|
+
if (shouldRestartBrokerForCliMtime(mtime, lastMtime)) {
|
|
122259
122769
|
const uid = process.getuid();
|
|
122260
122770
|
const plistPath = join32(homedir24(), "Library", "LaunchAgents", "dev.openscout.broker.plist");
|
|
122261
122771
|
spawnSync3("launchctl", ["bootout", `gui/${uid}/dev.openscout.broker`], { stdio: "ignore" });
|
|
122262
|
-
await new Promise((
|
|
122772
|
+
await new Promise((resolve19) => setTimeout(resolve19, 1500));
|
|
122263
122773
|
spawnSync3("launchctl", ["bootstrap", `gui/${uid}`, plistPath], { stdio: "ignore" });
|
|
122264
|
-
await new Promise((
|
|
122774
|
+
await new Promise((resolve19) => setTimeout(resolve19, 2000));
|
|
122265
122775
|
}
|
|
122266
122776
|
if (!existsSync25(checkpointDir)) {
|
|
122267
|
-
|
|
122777
|
+
mkdirSync13(checkpointDir, { recursive: true });
|
|
122268
122778
|
}
|
|
122269
|
-
writeFileSync9(mtimePath, String(
|
|
122779
|
+
writeFileSync9(mtimePath, String(mtime), { encoding: "utf8", flag: "w" });
|
|
122270
122780
|
} catch {}
|
|
122271
122781
|
}
|
|
122272
122782
|
try {
|