@openscout/scout 0.2.68 → 0.2.69
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/bin/openscout-runtime.mjs +11 -0
- package/dist/client/assets/addon-fit-DtSNdpy5.js +1 -0
- package/dist/client/assets/addon-webgl-YYNKPQUg.js +82 -0
- package/dist/client/assets/index-5-XOQrKH.js +186 -0
- package/dist/client/assets/index-BnA2HAbt.css +1 -0
- package/dist/client/assets/xterm-fBtFsYpq.js +34 -0
- package/dist/client/index.html +3 -3
- package/dist/main.mjs +2097 -504
- package/dist/openscout-terminal-relay.mjs +678 -0
- package/dist/pair-supervisor.mjs +1728 -183
- package/dist/runtime/base-daemon.mjs +19 -0
- package/dist/runtime/broker-daemon.mjs +2502 -382
- package/dist/runtime/broker-process-manager.mjs +11 -0
- package/dist/runtime/mesh-discover.mjs +11 -0
- package/dist/scout-control-plane-web.mjs +3220 -480
- package/dist/scout-web-server.mjs +3220 -480
- package/package.json +4 -2
- package/dist/client/assets/addon-fit_hudsonkit_false-DSvcGNZx.js +0 -1
- package/dist/client/assets/addon-webgl_hudsonkit_false-1rrLEmjL.js +0 -1
- package/dist/client/assets/index-R2y6GOWl.js +0 -184
- package/dist/client/assets/index-bOmc2x1_.css +0 -1
- package/dist/client/assets/xterm_hudsonkit_false-B2TbElXJ.js +0 -1
package/dist/main.mjs
CHANGED
|
@@ -815,6 +815,17 @@ function assertValidUnblockRequestEvent(event, record) {
|
|
|
815
815
|
throw new Error(errors.join("; "));
|
|
816
816
|
}
|
|
817
817
|
}
|
|
818
|
+
// ../protocol/src/lifecycle.ts
|
|
819
|
+
var TERMINAL_INVOCATION_STATES;
|
|
820
|
+
var init_lifecycle = __esm(() => {
|
|
821
|
+
TERMINAL_INVOCATION_STATES = new Set([
|
|
822
|
+
"completed",
|
|
823
|
+
"failed",
|
|
824
|
+
"cancelled",
|
|
825
|
+
"expired"
|
|
826
|
+
]);
|
|
827
|
+
});
|
|
828
|
+
|
|
818
829
|
// ../protocol/src/permission-policy.ts
|
|
819
830
|
function normalizeScoutPermissionProfile(value) {
|
|
820
831
|
const normalized = value?.trim().replaceAll("-", "_");
|
|
@@ -901,6 +912,9 @@ function parsePrefixedRouteTarget(prefix, rawValue) {
|
|
|
901
912
|
if (prefix === "id" || prefix === "agent-id" || prefix === "agent_id") {
|
|
902
913
|
return { kind: "agent_id", agentId: value, value: `id:${value}` };
|
|
903
914
|
}
|
|
915
|
+
if (prefix === "session" || prefix === "session-id" || prefix === "session_id" || prefix === "s") {
|
|
916
|
+
return { kind: "session_id", sessionId: value, value: `session:${value}` };
|
|
917
|
+
}
|
|
904
918
|
if (prefix === "channel" || prefix === "chan" || prefix === "ch") {
|
|
905
919
|
return { kind: "channel", channel: value, value: `channel:${value}` };
|
|
906
920
|
}
|
|
@@ -1003,15 +1017,20 @@ var init_inbox = __esm(() => {
|
|
|
1003
1017
|
"deferred"
|
|
1004
1018
|
];
|
|
1005
1019
|
});
|
|
1020
|
+
// ../protocol/src/cursor-transport.ts
|
|
1021
|
+
var init_cursor_transport = () => {};
|
|
1022
|
+
|
|
1006
1023
|
// ../protocol/src/index.ts
|
|
1007
1024
|
var init_src = __esm(() => {
|
|
1008
1025
|
init_agent_identity();
|
|
1009
1026
|
init_agent_address();
|
|
1010
1027
|
init_agent_selectors();
|
|
1028
|
+
init_lifecycle();
|
|
1011
1029
|
init_agent_runs();
|
|
1012
1030
|
init_scout_composer();
|
|
1013
1031
|
init_inbox();
|
|
1014
1032
|
init_permission_policy();
|
|
1033
|
+
init_cursor_transport();
|
|
1015
1034
|
});
|
|
1016
1035
|
|
|
1017
1036
|
// ../../apps/desktop/src/cli/options.ts
|
|
@@ -1140,6 +1159,15 @@ function parseComposerRoutedBody(input, commandName, currentDirectory) {
|
|
|
1140
1159
|
message: parsed.body
|
|
1141
1160
|
};
|
|
1142
1161
|
}
|
|
1162
|
+
if (target.kind === "session_id") {
|
|
1163
|
+
if (commandName === "send") {
|
|
1164
|
+
throw new ScoutCliError("send route operator must target an agent label, ref, channel, or broadcast");
|
|
1165
|
+
}
|
|
1166
|
+
return {
|
|
1167
|
+
targetLabel: `session:${target.sessionId}`,
|
|
1168
|
+
message: parsed.body
|
|
1169
|
+
};
|
|
1170
|
+
}
|
|
1143
1171
|
if (target.kind === "project_path") {
|
|
1144
1172
|
if (commandName === "send") {
|
|
1145
1173
|
throw new ScoutCliError("send route operator must target an agent label, ref, channel, or broadcast");
|
|
@@ -1627,6 +1655,7 @@ function parseChannelCommandOptions(args, defaultCurrentDirectory) {
|
|
|
1627
1655
|
const parsed = parseContextRootPrefix(args, defaultCurrentDirectory);
|
|
1628
1656
|
let channel;
|
|
1629
1657
|
let latest;
|
|
1658
|
+
let markRead = false;
|
|
1630
1659
|
for (let index = 0;index < parsed.args.length; index += 1) {
|
|
1631
1660
|
const current = parsed.args[index] ?? "";
|
|
1632
1661
|
if (current === "--channel" || current.startsWith("--channel=")) {
|
|
@@ -1645,20 +1674,28 @@ function parseChannelCommandOptions(args, defaultCurrentDirectory) {
|
|
|
1645
1674
|
index = value.nextIndex;
|
|
1646
1675
|
continue;
|
|
1647
1676
|
}
|
|
1677
|
+
if (current === "--mark-read" || current === "--read" || current === "--clear") {
|
|
1678
|
+
markRead = true;
|
|
1679
|
+
continue;
|
|
1680
|
+
}
|
|
1648
1681
|
if (!current.startsWith("-") && !channel) {
|
|
1649
1682
|
channel = current;
|
|
1650
1683
|
continue;
|
|
1651
1684
|
}
|
|
1652
1685
|
unexpectedArgs("channel", args);
|
|
1653
1686
|
}
|
|
1654
|
-
if (
|
|
1655
|
-
throw new ScoutCliError("
|
|
1687
|
+
if (latest && markRead) {
|
|
1688
|
+
throw new ScoutCliError("provide either --latest or --mark-read, not both");
|
|
1689
|
+
}
|
|
1690
|
+
if (channel && !latest && !markRead) {
|
|
1691
|
+
throw new ScoutCliError("channel name is only valid with --latest or --mark-read");
|
|
1656
1692
|
}
|
|
1657
1693
|
return {
|
|
1658
1694
|
currentDirectory: parsed.currentDirectory,
|
|
1659
1695
|
args: parsed.args,
|
|
1660
1696
|
channel,
|
|
1661
|
-
latest
|
|
1697
|
+
latest,
|
|
1698
|
+
markRead
|
|
1662
1699
|
};
|
|
1663
1700
|
}
|
|
1664
1701
|
function parseInboxCommandOptions(args, defaultCurrentDirectory) {
|
|
@@ -1805,6 +1842,7 @@ function parseCardCreateCommandOptions(args, defaultCurrentDirectory) {
|
|
|
1805
1842
|
let permissionProfile;
|
|
1806
1843
|
let requesterId = null;
|
|
1807
1844
|
let noInput = false;
|
|
1845
|
+
let oneTimeUse = false;
|
|
1808
1846
|
for (let index = 0;index < parsed.args.length; index += 1) {
|
|
1809
1847
|
const current = parsed.args[index] ?? "";
|
|
1810
1848
|
if (current === "--name" || current.startsWith("--name=")) {
|
|
@@ -1868,6 +1906,10 @@ function parseCardCreateCommandOptions(args, defaultCurrentDirectory) {
|
|
|
1868
1906
|
noInput = true;
|
|
1869
1907
|
continue;
|
|
1870
1908
|
}
|
|
1909
|
+
if (current === "--one-time") {
|
|
1910
|
+
oneTimeUse = true;
|
|
1911
|
+
continue;
|
|
1912
|
+
}
|
|
1871
1913
|
if (current.startsWith("--")) {
|
|
1872
1914
|
unexpectedArgs("card create", args);
|
|
1873
1915
|
}
|
|
@@ -1887,7 +1929,8 @@ function parseCardCreateCommandOptions(args, defaultCurrentDirectory) {
|
|
|
1887
1929
|
reasoningEffort,
|
|
1888
1930
|
permissionProfile,
|
|
1889
1931
|
requesterId,
|
|
1890
|
-
noInput
|
|
1932
|
+
noInput,
|
|
1933
|
+
oneTimeUse
|
|
1891
1934
|
};
|
|
1892
1935
|
}
|
|
1893
1936
|
function parseTuiCommandOptions(args, defaultCurrentDirectory) {
|
|
@@ -6209,6 +6252,15 @@ async function maybeReadJsonFromActiveScoutBrokerService(baseUrl, path) {
|
|
|
6209
6252
|
includeAcknowledged: url.searchParams.get("includeAcknowledged") === "1" || url.searchParams.get("includeAcknowledged") === "true"
|
|
6210
6253
|
}));
|
|
6211
6254
|
}
|
|
6255
|
+
const invocationLifecycleMatch = url.pathname.match(/^\/v1\/invocations\/([^/]+)\/lifecycle$/);
|
|
6256
|
+
if (invocationLifecycleMatch) {
|
|
6257
|
+
if (!service.readInvocationLifecycle) {
|
|
6258
|
+
return unhandled();
|
|
6259
|
+
}
|
|
6260
|
+
return handled(await service.readInvocationLifecycle({
|
|
6261
|
+
invocationId: decodeURIComponent(invocationLifecycleMatch[1] ?? "")
|
|
6262
|
+
}));
|
|
6263
|
+
}
|
|
6212
6264
|
if (url.pathname === "/v1/activity") {
|
|
6213
6265
|
if (!service.readActivity) {
|
|
6214
6266
|
return unhandled();
|
|
@@ -7089,6 +7141,17 @@ async function fetchHealthSnapshot(config) {
|
|
|
7089
7141
|
nodes: payload.counts.nodes ?? 0,
|
|
7090
7142
|
actors: payload.counts.actors ?? 0,
|
|
7091
7143
|
agents: payload.counts.agents ?? 0,
|
|
7144
|
+
agentRecords: payload.counts.agentRecords,
|
|
7145
|
+
rawAgentRecords: payload.counts.rawAgentRecords,
|
|
7146
|
+
configuredAgents: payload.counts.configuredAgents,
|
|
7147
|
+
scoutManagedAgents: payload.counts.scoutManagedAgents,
|
|
7148
|
+
currentAgentRegistrations: payload.counts.currentAgentRegistrations,
|
|
7149
|
+
localAgentRegistrations: payload.counts.localAgentRegistrations,
|
|
7150
|
+
remoteAgentRegistrations: payload.counts.remoteAgentRegistrations,
|
|
7151
|
+
staleAgentRegistrations: payload.counts.staleAgentRegistrations,
|
|
7152
|
+
retiredAgentRegistrations: payload.counts.retiredAgentRegistrations,
|
|
7153
|
+
oneTimeAgentCards: payload.counts.oneTimeAgentCards,
|
|
7154
|
+
persistentAgentCards: payload.counts.persistentAgentCards,
|
|
7092
7155
|
conversations: payload.counts.conversations ?? 0,
|
|
7093
7156
|
messages: payload.counts.messages ?? 0,
|
|
7094
7157
|
flights: payload.counts.flights ?? 0,
|
|
@@ -7261,6 +7324,9 @@ var init_broker_process_manager = __esm(() => {
|
|
|
7261
7324
|
}
|
|
7262
7325
|
});
|
|
7263
7326
|
|
|
7327
|
+
// ../runtime/src/dispatch-stalled.ts
|
|
7328
|
+
var init_dispatch_stalled = () => {};
|
|
7329
|
+
|
|
7264
7330
|
// ../runtime/src/managed-agent-environment.ts
|
|
7265
7331
|
function managedAgentEnvironmentEntries(options) {
|
|
7266
7332
|
const agentName = options.agentName.trim();
|
|
@@ -13525,6 +13591,15 @@ function readCodexAppServerReasoningEffortFromLaunchArgs(launchArgs) {
|
|
|
13525
13591
|
}
|
|
13526
13592
|
return null;
|
|
13527
13593
|
}
|
|
13594
|
+
function codexAppServerExitMessage(input) {
|
|
13595
|
+
if (input.exitKind === "proactive_shutdown") {
|
|
13596
|
+
return `Codex app-server session for ${input.agentName} was stopped by OpenScout` + (input.reason ? `: ${input.reason}` : "") + ".";
|
|
13597
|
+
}
|
|
13598
|
+
if (input.exitKind === "external_sigterm") {
|
|
13599
|
+
return `Codex app-server for ${input.agentName} was interrupted by SIGTERM.`;
|
|
13600
|
+
}
|
|
13601
|
+
return `Codex app-server exited for ${input.agentName}` + (input.exitCode !== null ? ` with code ${input.exitCode}` : "") + (input.signal ? ` (${input.signal})` : "");
|
|
13602
|
+
}
|
|
13528
13603
|
function resolveRequesterTimeoutMs2(timeoutMs) {
|
|
13529
13604
|
if (typeof timeoutMs === "number" && Number.isFinite(timeoutMs) && timeoutMs > 0) {
|
|
13530
13605
|
return timeoutMs;
|
|
@@ -13696,6 +13771,7 @@ class CodexAppServerSession {
|
|
|
13696
13771
|
activeTurn = null;
|
|
13697
13772
|
threadId = null;
|
|
13698
13773
|
threadPath = null;
|
|
13774
|
+
proactiveShutdown = null;
|
|
13699
13775
|
lastConfigSignature;
|
|
13700
13776
|
constructor(options) {
|
|
13701
13777
|
this.options = options;
|
|
@@ -13826,13 +13902,23 @@ class CodexAppServerSession {
|
|
|
13826
13902
|
});
|
|
13827
13903
|
}
|
|
13828
13904
|
async shutdown(options = {}) {
|
|
13905
|
+
this.proactiveShutdown = {
|
|
13906
|
+
reason: options.reason ?? (options.resetThread ? "OpenScout reset the app-server session" : "OpenScout stopped the app-server session")
|
|
13907
|
+
};
|
|
13908
|
+
const stoppedError = new CodexAppServerExitError({
|
|
13909
|
+
agentName: this.options.agentName,
|
|
13910
|
+
exitKind: "proactive_shutdown",
|
|
13911
|
+
exitCode: null,
|
|
13912
|
+
signal: null,
|
|
13913
|
+
reason: this.proactiveShutdown.reason
|
|
13914
|
+
});
|
|
13829
13915
|
const activeTurn = this.activeTurn;
|
|
13830
13916
|
this.activeTurn = null;
|
|
13831
13917
|
if (activeTurn) {
|
|
13832
|
-
activeTurn.reject(
|
|
13918
|
+
activeTurn.reject(stoppedError);
|
|
13833
13919
|
}
|
|
13834
13920
|
for (const pending of this.pendingRequests.values()) {
|
|
13835
|
-
pending.reject(
|
|
13921
|
+
pending.reject(stoppedError);
|
|
13836
13922
|
}
|
|
13837
13923
|
this.pendingRequests.clear();
|
|
13838
13924
|
const child = this.process;
|
|
@@ -13842,7 +13928,7 @@ class CodexAppServerSession {
|
|
|
13842
13928
|
if (child && child.exitCode === null && !child.killed) {
|
|
13843
13929
|
child.kill("SIGTERM");
|
|
13844
13930
|
await new Promise((resolve8) => setTimeout(resolve8, 250));
|
|
13845
|
-
if (child.exitCode === null &&
|
|
13931
|
+
if (child.exitCode === null && child.signalCode === null) {
|
|
13846
13932
|
child.kill("SIGKILL");
|
|
13847
13933
|
}
|
|
13848
13934
|
}
|
|
@@ -13893,6 +13979,7 @@ class CodexAppServerSession {
|
|
|
13893
13979
|
await mkdir5(this.options.runtimeDirectory, { recursive: true });
|
|
13894
13980
|
await mkdir5(this.options.logsDirectory, { recursive: true });
|
|
13895
13981
|
await writeFile5(join14(this.options.runtimeDirectory, "prompt.txt"), this.options.systemPrompt);
|
|
13982
|
+
this.proactiveShutdown = null;
|
|
13896
13983
|
const codexExecutable = resolveCodexExecutable();
|
|
13897
13984
|
const launchArgs = normalizeCodexAppServerLaunchArgs(this.options.launchArgs);
|
|
13898
13985
|
const env = buildManagedAgentEnvironment({
|
|
@@ -13932,7 +14019,16 @@ class CodexAppServerSession {
|
|
|
13932
14019
|
this.failSession(new Error(`Codex app-server failed for ${this.options.agentName}: ${errorMessage4(error)}`));
|
|
13933
14020
|
});
|
|
13934
14021
|
child.once("exit", (code, signal) => {
|
|
13935
|
-
|
|
14022
|
+
const proactiveShutdown = this.proactiveShutdown;
|
|
14023
|
+
if (proactiveShutdown) {
|
|
14024
|
+
this.handleProactiveProcessExit(child, proactiveShutdown, code, signal);
|
|
14025
|
+
return;
|
|
14026
|
+
}
|
|
14027
|
+
this.failSession(new CodexAppServerExitError({
|
|
14028
|
+
agentName: this.options.agentName,
|
|
14029
|
+
exitCode: code,
|
|
14030
|
+
signal
|
|
14031
|
+
}));
|
|
13936
14032
|
});
|
|
13937
14033
|
await this.request("initialize", {
|
|
13938
14034
|
clientInfo: {
|
|
@@ -14267,6 +14363,23 @@ class CodexAppServerSession {
|
|
|
14267
14363
|
}
|
|
14268
14364
|
this.pendingRequests.clear();
|
|
14269
14365
|
appendFile3(this.stderrLogPath, `[openscout] ${error.message}
|
|
14366
|
+
`).catch(() => {
|
|
14367
|
+
return;
|
|
14368
|
+
});
|
|
14369
|
+
this.persistState();
|
|
14370
|
+
}
|
|
14371
|
+
handleProactiveProcessExit(child, shutdown, code, signal) {
|
|
14372
|
+
if (this.process === child) {
|
|
14373
|
+
this.process = null;
|
|
14374
|
+
}
|
|
14375
|
+
this.proactiveShutdown = null;
|
|
14376
|
+
this.starting = null;
|
|
14377
|
+
const exitDetail = [
|
|
14378
|
+
code !== null ? `code ${code}` : null,
|
|
14379
|
+
signal
|
|
14380
|
+
].filter(Boolean).join(", ");
|
|
14381
|
+
const detail = exitDetail ? ` (${exitDetail})` : "";
|
|
14382
|
+
appendFile3(this.stderrLogPath, `[openscout] Codex app-server stopped for ${this.options.agentName}: ${shutdown.reason}${detail}
|
|
14270
14383
|
`).catch(() => {
|
|
14271
14384
|
return;
|
|
14272
14385
|
});
|
|
@@ -14337,7 +14450,10 @@ function getOrCreateSession2(options) {
|
|
|
14337
14450
|
if (existing.matches(options)) {
|
|
14338
14451
|
return existing;
|
|
14339
14452
|
}
|
|
14340
|
-
existing.shutdown({
|
|
14453
|
+
existing.shutdown({
|
|
14454
|
+
resetThread: true,
|
|
14455
|
+
reason: "OpenScout replaced the app-server session after its launch options changed"
|
|
14456
|
+
});
|
|
14341
14457
|
sessions2.delete(key);
|
|
14342
14458
|
}
|
|
14343
14459
|
const session = new CodexAppServerSession(options);
|
|
@@ -14368,13 +14484,36 @@ async function shutdownCodexAppServerAgent(options, shutdownOptions = {}) {
|
|
|
14368
14484
|
sessions2.delete(key);
|
|
14369
14485
|
await session.shutdown(shutdownOptions);
|
|
14370
14486
|
}
|
|
14371
|
-
var SESSION_CATALOG_FILENAME2 = "session-catalog.json", SESSION_CATALOG_MAX_ENTRIES2 = 64, CODEX_ROLLOUT_STALE_ACTIVE_TURN_MS, sessions2;
|
|
14487
|
+
var CodexAppServerExitError, SESSION_CATALOG_FILENAME2 = "session-catalog.json", SESSION_CATALOG_MAX_ENTRIES2 = 64, CODEX_ROLLOUT_STALE_ACTIVE_TURN_MS, sessions2;
|
|
14372
14488
|
var init_codex_app_server = __esm(() => {
|
|
14373
14489
|
init_src2();
|
|
14374
14490
|
init_topology();
|
|
14375
14491
|
init_codex_executable();
|
|
14376
14492
|
init_requester_timeout();
|
|
14377
14493
|
init_codex_executable();
|
|
14494
|
+
CodexAppServerExitError = class CodexAppServerExitError extends Error {
|
|
14495
|
+
code = "CODEX_APP_SERVER_EXIT";
|
|
14496
|
+
exitKind;
|
|
14497
|
+
agentName;
|
|
14498
|
+
exitCode;
|
|
14499
|
+
signal;
|
|
14500
|
+
reason;
|
|
14501
|
+
noteworthy;
|
|
14502
|
+
constructor(input) {
|
|
14503
|
+
const exitKind = input.exitKind ?? (input.signal === "SIGTERM" ? "external_sigterm" : "unexpected_exit");
|
|
14504
|
+
super(codexAppServerExitMessage({
|
|
14505
|
+
...input,
|
|
14506
|
+
exitKind
|
|
14507
|
+
}));
|
|
14508
|
+
this.name = "CodexAppServerExitError";
|
|
14509
|
+
this.exitKind = exitKind;
|
|
14510
|
+
this.agentName = input.agentName;
|
|
14511
|
+
this.exitCode = input.exitCode;
|
|
14512
|
+
this.signal = input.signal;
|
|
14513
|
+
this.reason = input.reason ?? null;
|
|
14514
|
+
this.noteworthy = exitKind !== "unexpected_exit";
|
|
14515
|
+
}
|
|
14516
|
+
};
|
|
14378
14517
|
CODEX_ROLLOUT_STALE_ACTIVE_TURN_MS = 10 * 60 * 1000;
|
|
14379
14518
|
sessions2 = new Map;
|
|
14380
14519
|
});
|
|
@@ -14470,11 +14609,47 @@ var init_permission_policy2 = __esm(() => {
|
|
|
14470
14609
|
init_src();
|
|
14471
14610
|
});
|
|
14472
14611
|
|
|
14612
|
+
// ../runtime/src/user-config.ts
|
|
14613
|
+
import { existsSync as existsSync11, readFileSync as readFileSync6, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "fs";
|
|
14614
|
+
import { homedir as homedir12 } from "os";
|
|
14615
|
+
import { dirname as dirname8, join as join15 } from "path";
|
|
14616
|
+
function userConfigPath() {
|
|
14617
|
+
return join15(process.env.OPENSCOUT_HOME ?? join15(homedir12(), ".openscout"), "user.json");
|
|
14618
|
+
}
|
|
14619
|
+
function loadUserConfig() {
|
|
14620
|
+
const configPath = userConfigPath();
|
|
14621
|
+
if (!existsSync11(configPath))
|
|
14622
|
+
return {};
|
|
14623
|
+
try {
|
|
14624
|
+
return JSON.parse(readFileSync6(configPath, "utf8"));
|
|
14625
|
+
} catch {
|
|
14626
|
+
return {};
|
|
14627
|
+
}
|
|
14628
|
+
}
|
|
14629
|
+
function saveUserConfig(config) {
|
|
14630
|
+
const configPath = userConfigPath();
|
|
14631
|
+
mkdirSync3(dirname8(configPath), { recursive: true });
|
|
14632
|
+
writeFileSync3(configPath, JSON.stringify(config, null, 2) + `
|
|
14633
|
+
`, "utf8");
|
|
14634
|
+
}
|
|
14635
|
+
function resolveOperatorName() {
|
|
14636
|
+
const config = loadUserConfig();
|
|
14637
|
+
return config.name?.trim() || process.env.OPENSCOUT_OPERATOR_NAME?.trim() || process.env.USER?.trim() || "operator";
|
|
14638
|
+
}
|
|
14639
|
+
function normalizeHandle(value) {
|
|
14640
|
+
return value?.trim().replace(/^@+/, "") ?? "";
|
|
14641
|
+
}
|
|
14642
|
+
function resolveOperatorHandle() {
|
|
14643
|
+
const config = loadUserConfig();
|
|
14644
|
+
return normalizeHandle(config.handle) || normalizeHandle(process.env.OPENSCOUT_OPERATOR_HANDLE) || normalizeHandle(config.name) || normalizeHandle(process.env.OPENSCOUT_OPERATOR_NAME) || normalizeHandle(process.env.USER) || "operator";
|
|
14645
|
+
}
|
|
14646
|
+
var init_user_config = () => {};
|
|
14647
|
+
|
|
14473
14648
|
// ../runtime/src/local-agents.ts
|
|
14474
14649
|
import { execFileSync as execFileSync4, execSync } from "child_process";
|
|
14475
|
-
import { existsSync as
|
|
14650
|
+
import { existsSync as existsSync12, readFileSync as readFileSync7 } from "fs";
|
|
14476
14651
|
import { mkdir as mkdir6, rm as rm5, stat as stat3, writeFile as writeFile6 } from "fs/promises";
|
|
14477
|
-
import { basename as basename7, dirname as
|
|
14652
|
+
import { basename as basename7, dirname as dirname9, join as join16, resolve as resolve8 } from "path";
|
|
14478
14653
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
14479
14654
|
function resolveRelayHub() {
|
|
14480
14655
|
return resolveOpenScoutSupportPaths().relayHubDirectory;
|
|
@@ -14485,14 +14660,14 @@ function resolveProjectsRoot(projectPath) {
|
|
|
14485
14660
|
}
|
|
14486
14661
|
try {
|
|
14487
14662
|
const supportPaths = resolveOpenScoutSupportPaths();
|
|
14488
|
-
if (!
|
|
14489
|
-
return
|
|
14663
|
+
if (!existsSync12(supportPaths.settingsPath)) {
|
|
14664
|
+
return dirname9(projectPath);
|
|
14490
14665
|
}
|
|
14491
|
-
const raw = JSON.parse(
|
|
14666
|
+
const raw = JSON.parse(readFileSync7(supportPaths.settingsPath, "utf8"));
|
|
14492
14667
|
const workspaceRoot = raw.discovery?.workspaceRoots?.find((entry) => typeof entry === "string" && entry.trim().length > 0);
|
|
14493
|
-
return workspaceRoot ? resolve8(workspaceRoot) :
|
|
14668
|
+
return workspaceRoot ? resolve8(workspaceRoot) : dirname9(projectPath);
|
|
14494
14669
|
} catch {
|
|
14495
|
-
return
|
|
14670
|
+
return dirname9(projectPath);
|
|
14496
14671
|
}
|
|
14497
14672
|
}
|
|
14498
14673
|
function resolveBrokerUrl() {
|
|
@@ -14502,7 +14677,7 @@ function nowSeconds2() {
|
|
|
14502
14677
|
return Math.floor(Date.now() / 1000);
|
|
14503
14678
|
}
|
|
14504
14679
|
function scoutCliPath() {
|
|
14505
|
-
return
|
|
14680
|
+
return join16(OPENSCOUT_REPO_ROOT, "packages", "cli", "bin", "scout.mjs");
|
|
14506
14681
|
}
|
|
14507
14682
|
function legacyNodeBrokerRelayCommand() {
|
|
14508
14683
|
return `node ${JSON.stringify(scoutCliPath())}`;
|
|
@@ -14515,13 +14690,13 @@ function titleCaseLocalAgentName(value) {
|
|
|
14515
14690
|
}
|
|
14516
14691
|
function resolveScoutSkillPath() {
|
|
14517
14692
|
const candidatePaths = [
|
|
14518
|
-
|
|
14519
|
-
|
|
14520
|
-
|
|
14521
|
-
|
|
14693
|
+
join16(OPENSCOUT_REPO_ROOT, ".agents", "skills", "scout", "SKILL.md"),
|
|
14694
|
+
join16(process.env.HOME ?? "", ".agents", "skills", "scout", "SKILL.md"),
|
|
14695
|
+
join16(OPENSCOUT_REPO_ROOT, ".agents", "skills", "relay-agent-comms", "SKILL.md"),
|
|
14696
|
+
join16(process.env.HOME ?? "", ".agents", "skills", "relay-agent-comms", "SKILL.md")
|
|
14522
14697
|
];
|
|
14523
14698
|
for (const path of candidatePaths) {
|
|
14524
|
-
if (
|
|
14699
|
+
if (existsSync12(path)) {
|
|
14525
14700
|
return path;
|
|
14526
14701
|
}
|
|
14527
14702
|
}
|
|
@@ -14629,6 +14804,74 @@ function buildLocalAgentSystemPromptTemplate() {
|
|
|
14629
14804
|
].join(`
|
|
14630
14805
|
`);
|
|
14631
14806
|
}
|
|
14807
|
+
function normalizeOperatorHandleSegment(value) {
|
|
14808
|
+
return normalizeAgentSelectorSegment(value?.trim().replace(/^@+/, "") ?? "") || "operator";
|
|
14809
|
+
}
|
|
14810
|
+
function resolveOperatorAugmentAgentName() {
|
|
14811
|
+
return `${normalizeOperatorHandleSegment(resolveOperatorHandle())}-ai`;
|
|
14812
|
+
}
|
|
14813
|
+
function operatorAugmentAgentNameCandidates() {
|
|
14814
|
+
return new Set([
|
|
14815
|
+
resolveOperatorAugmentAgentName(),
|
|
14816
|
+
"operator-ai"
|
|
14817
|
+
]);
|
|
14818
|
+
}
|
|
14819
|
+
function buildOperatorAugmentSystemPromptTemplate(input = {}) {
|
|
14820
|
+
const operatorHandle = normalizeOperatorHandleSegment(input.operatorHandle ?? resolveOperatorHandle());
|
|
14821
|
+
const augmentHandle = normalizeOperatorHandleSegment(input.augmentHandle ?? `${operatorHandle}-ai`);
|
|
14822
|
+
const humanLabel = `@${operatorHandle}`;
|
|
14823
|
+
const augmentLabel = `@${augmentHandle}`;
|
|
14824
|
+
return [
|
|
14825
|
+
"{{base_prompt}}",
|
|
14826
|
+
"",
|
|
14827
|
+
`You are the augmented counterpart to the human Scout operator ${humanLabel}.`,
|
|
14828
|
+
`${humanLabel} is the human. ${augmentLabel} is the AI-augmented looper with a human in the loop.`,
|
|
14829
|
+
`Do not impersonate ${humanLabel}. Speak and act as ${augmentLabel}, and involve ${humanLabel} only when human judgment or approval is the real next dependency.`,
|
|
14830
|
+
"",
|
|
14831
|
+
"Operating loop:",
|
|
14832
|
+
" - Keep long-running conversations in the same DM or invocation thread whenever possible.",
|
|
14833
|
+
" - Maintain continuity across turns: track the goal, decisions made, open questions, blockers, and promised follow-ups.",
|
|
14834
|
+
" - For efforts that span many turns, many files, or more than one working session, create or update a durable note/checkpoint when you have write access, then point to it briefly.",
|
|
14835
|
+
" - Prefer continuing from a concise recap over resetting context. If context is aging, summarize the useful state and keep moving.",
|
|
14836
|
+
` - Be explicit about the next responsible owner: ${augmentLabel}, ${humanLabel}, or another named agent.`,
|
|
14837
|
+
"",
|
|
14838
|
+
`When to invoke ${humanLabel}:`,
|
|
14839
|
+
" - Approval is needed for destructive, irreversible, public, financial, security-sensitive, credential, privacy, or cross-project priority decisions.",
|
|
14840
|
+
` - The task depends on taste, intent, product direction, personal context, or a choice only ${humanLabel} can make.`,
|
|
14841
|
+
" - You are blocked after a reasonable local attempt and the unblock request can be stated as a short concrete question.",
|
|
14842
|
+
" - A result is materially uncertain and acting without human input could waste meaningful time or create cleanup work.",
|
|
14843
|
+
" - You need permission to interrupt, wake, or redirect other people or agents outside the current work venue.",
|
|
14844
|
+
"",
|
|
14845
|
+
`How to invoke ${humanLabel}:`,
|
|
14846
|
+
" - Keep the ask concise: context, the decision needed, the default you recommend, and the consequence of no answer.",
|
|
14847
|
+
" - Use the same DM/thread when it exists. Do not broadcast human-loop requests.",
|
|
14848
|
+
` - If a reply is required before work can proceed, say that ${humanLabel} owns the next move and stop claiming progress.`,
|
|
14849
|
+
" - If work can continue safely, state the assumption and continue without waiting.",
|
|
14850
|
+
"",
|
|
14851
|
+
`Do not invoke ${humanLabel} for:`,
|
|
14852
|
+
" - Routine status updates, obvious implementation details, command outputs, local orientation, or reversible low-risk cleanup.",
|
|
14853
|
+
" - Ambiguity that you can resolve by reading the repo, checking Scout state, or asking the correct specialist agent.",
|
|
14854
|
+
"",
|
|
14855
|
+
"{{project_context}}",
|
|
14856
|
+
"",
|
|
14857
|
+
"{{collaboration_prompt}}",
|
|
14858
|
+
"",
|
|
14859
|
+
"{{protocol_prompt}}"
|
|
14860
|
+
].join(`
|
|
14861
|
+
`);
|
|
14862
|
+
}
|
|
14863
|
+
function operatorAugmentDefaultsForDefinitionId(definitionId) {
|
|
14864
|
+
const normalizedDefinitionId = normalizeAgentSelectorSegment(definitionId);
|
|
14865
|
+
if (!normalizedDefinitionId || !operatorAugmentAgentNameCandidates().has(normalizedDefinitionId)) {
|
|
14866
|
+
return null;
|
|
14867
|
+
}
|
|
14868
|
+
return {
|
|
14869
|
+
displayName: titleCaseLocalAgentName(normalizedDefinitionId),
|
|
14870
|
+
systemPrompt: buildOperatorAugmentSystemPromptTemplate({
|
|
14871
|
+
augmentHandle: normalizedDefinitionId
|
|
14872
|
+
})
|
|
14873
|
+
};
|
|
14874
|
+
}
|
|
14632
14875
|
function renderLocalAgentSystemPromptTemplate(template, context, options = {}) {
|
|
14633
14876
|
const basePrompt = buildLocalAgentBasePrompt(context);
|
|
14634
14877
|
const projectContext = buildLocalAgentProjectContextPrompt(context);
|
|
@@ -14783,13 +15026,20 @@ function expandHomePath4(value) {
|
|
|
14783
15026
|
return process.env.HOME ?? process.cwd();
|
|
14784
15027
|
}
|
|
14785
15028
|
if (value.startsWith("~/")) {
|
|
14786
|
-
return
|
|
15029
|
+
return join16(process.env.HOME ?? process.cwd(), value.slice(2));
|
|
14787
15030
|
}
|
|
14788
15031
|
return value;
|
|
14789
15032
|
}
|
|
14790
15033
|
function normalizeProjectPath(value) {
|
|
14791
15034
|
return resolve8(expandHomePath4(value.trim() || "."));
|
|
14792
15035
|
}
|
|
15036
|
+
function compactHomePath(value) {
|
|
15037
|
+
const home = process.env.HOME;
|
|
15038
|
+
if (!home) {
|
|
15039
|
+
return value;
|
|
15040
|
+
}
|
|
15041
|
+
return value.startsWith(home) ? value.replace(home, "~") : value;
|
|
15042
|
+
}
|
|
14793
15043
|
function normalizeTmuxSessionName2(value, agentId) {
|
|
14794
15044
|
const fallback = `relay-${agentId}`;
|
|
14795
15045
|
const trimmed = value?.trim() ?? "";
|
|
@@ -15043,6 +15293,21 @@ function applyRequestedRuntimeOptionsToLaunchArgs(harness, launchArgs, options)
|
|
|
15043
15293
|
...buildLaunchArgsForRequestedReasoningEffort(harness, requestedReasoningEffort)
|
|
15044
15294
|
];
|
|
15045
15295
|
}
|
|
15296
|
+
function setLaunchModelForHarness(harness, launchArgs, model) {
|
|
15297
|
+
const normalized = normalizeLaunchArgsForHarness(harness, launchArgs);
|
|
15298
|
+
if (model === undefined) {
|
|
15299
|
+
return normalized;
|
|
15300
|
+
}
|
|
15301
|
+
const stripped = stripLaunchModelForHarness(harness, normalized);
|
|
15302
|
+
const requestedModel = normalizeRequestedModel(model ?? undefined);
|
|
15303
|
+
if (!requestedModel) {
|
|
15304
|
+
return stripped;
|
|
15305
|
+
}
|
|
15306
|
+
return [
|
|
15307
|
+
...stripped,
|
|
15308
|
+
...buildLaunchArgsForRequestedModel(harness, requestedModel)
|
|
15309
|
+
];
|
|
15310
|
+
}
|
|
15046
15311
|
function defaultHarnessForOverride(override, fallback = "claude") {
|
|
15047
15312
|
return normalizeManagedHarness2(override.defaultHarness ?? override.runtime?.harness, fallback);
|
|
15048
15313
|
}
|
|
@@ -15163,6 +15428,31 @@ function recordForHarness(record, harnessOverride) {
|
|
|
15163
15428
|
permissionProfile: profile.permissionProfile
|
|
15164
15429
|
};
|
|
15165
15430
|
}
|
|
15431
|
+
function normalizeCardTimestamp(value) {
|
|
15432
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : undefined;
|
|
15433
|
+
}
|
|
15434
|
+
function normalizeLocalAgentCardLifecycle(value, now = Date.now()) {
|
|
15435
|
+
if (!value) {
|
|
15436
|
+
return;
|
|
15437
|
+
}
|
|
15438
|
+
const kind = value.kind === "one_time" ? "one_time" : value.kind === "persistent" ? "persistent" : undefined;
|
|
15439
|
+
if (!kind) {
|
|
15440
|
+
return;
|
|
15441
|
+
}
|
|
15442
|
+
const createdAt = normalizeCardTimestamp(value.createdAt) ?? now;
|
|
15443
|
+
const expiresAt = normalizeCardTimestamp(value.expiresAt);
|
|
15444
|
+
const maxUses = typeof value.maxUses === "number" && Number.isFinite(value.maxUses) && value.maxUses > 0 ? Math.floor(value.maxUses) : undefined;
|
|
15445
|
+
const createdById = value.createdById?.trim();
|
|
15446
|
+
const inboxConversationId = value.inboxConversationId?.trim();
|
|
15447
|
+
return {
|
|
15448
|
+
kind,
|
|
15449
|
+
createdAt,
|
|
15450
|
+
...createdById ? { createdById } : {},
|
|
15451
|
+
...expiresAt ? { expiresAt } : {},
|
|
15452
|
+
...maxUses ? { maxUses } : {},
|
|
15453
|
+
...inboxConversationId ? { inboxConversationId } : {}
|
|
15454
|
+
};
|
|
15455
|
+
}
|
|
15166
15456
|
function normalizeLocalAgentRecord(agentId, record) {
|
|
15167
15457
|
const cwd = normalizeProjectPath(record.cwd || process.cwd());
|
|
15168
15458
|
const projectRoot = normalizeProjectPath(record.projectRoot || cwd);
|
|
@@ -15192,7 +15482,8 @@ function normalizeLocalAgentRecord(agentId, record) {
|
|
|
15192
15482
|
capabilities: normalizeLocalAgentCapabilities(record.capabilities),
|
|
15193
15483
|
launchArgs: activeProfile?.launchArgs ?? normalizeLaunchArgsForHarness(harness, record.launchArgs),
|
|
15194
15484
|
permissionProfile: activeProfile?.permissionProfile ?? record.permissionProfile,
|
|
15195
|
-
registrationSource: record.registrationSource
|
|
15485
|
+
registrationSource: record.registrationSource,
|
|
15486
|
+
card: normalizeLocalAgentCardLifecycle(record.card)
|
|
15196
15487
|
};
|
|
15197
15488
|
}
|
|
15198
15489
|
function localAgentStatusFromRecord(agentId, record, source) {
|
|
@@ -15246,7 +15537,8 @@ function localAgentRecordFromRelayAgentOverride(agentId, override) {
|
|
|
15246
15537
|
harnessProfiles: override.harnessProfiles,
|
|
15247
15538
|
transport: normalizeLocalAgentTransport(override.runtime?.transport, normalizeLocalAgentHarness(override.runtime?.harness)),
|
|
15248
15539
|
capabilities: override.capabilities,
|
|
15249
|
-
launchArgs: override.launchArgs
|
|
15540
|
+
launchArgs: override.launchArgs,
|
|
15541
|
+
card: override.card
|
|
15250
15542
|
});
|
|
15251
15543
|
}
|
|
15252
15544
|
function relayAgentOverrideFromLocalAgentRecord(agentId, record, existing) {
|
|
@@ -15267,6 +15559,7 @@ function relayAgentOverrideFromLocalAgentRecord(agentId, record, existing) {
|
|
|
15267
15559
|
capabilities: normalizeLocalAgentCapabilities(normalizedRecord.capabilities),
|
|
15268
15560
|
defaultHarness: normalizeManagedHarness2(normalizedRecord.defaultHarness, "claude"),
|
|
15269
15561
|
harnessProfiles: normalizedRecord.harnessProfiles,
|
|
15562
|
+
...normalizedRecord.card ? { card: normalizedRecord.card } : {},
|
|
15270
15563
|
runtime: {
|
|
15271
15564
|
cwd: normalizeProjectPath(normalizedRecord.cwd),
|
|
15272
15565
|
harness: normalizeLocalAgentHarness(normalizedRecord.harness),
|
|
@@ -15276,6 +15569,245 @@ function relayAgentOverrideFromLocalAgentRecord(agentId, record, existing) {
|
|
|
15276
15569
|
}
|
|
15277
15570
|
};
|
|
15278
15571
|
}
|
|
15572
|
+
function buildLocalAgentConfigState(agentId, record) {
|
|
15573
|
+
const harness = normalizeLocalAgentHarness(record.harness);
|
|
15574
|
+
const launchArgs = normalizeLaunchArgsForHarness(harness, record.launchArgs);
|
|
15575
|
+
return {
|
|
15576
|
+
agentId,
|
|
15577
|
+
editable: true,
|
|
15578
|
+
model: readLaunchModelForHarness(harness, launchArgs) ?? null,
|
|
15579
|
+
permissionProfile: record.permissionProfile ?? null,
|
|
15580
|
+
systemPrompt: record.systemPrompt || buildLocalAgentSystemPromptTemplate(),
|
|
15581
|
+
runtime: {
|
|
15582
|
+
cwd: compactHomePath(record.cwd),
|
|
15583
|
+
harness,
|
|
15584
|
+
transport: normalizeLocalAgentTransport(record.transport, harness),
|
|
15585
|
+
sessionId: record.tmuxSession,
|
|
15586
|
+
wakePolicy: "on_demand"
|
|
15587
|
+
},
|
|
15588
|
+
launchArgs,
|
|
15589
|
+
capabilities: normalizeLocalAgentCapabilities(record.capabilities),
|
|
15590
|
+
applyMode: "restart",
|
|
15591
|
+
templateHint: LOCAL_AGENT_SYSTEM_PROMPT_TEMPLATE_HINT
|
|
15592
|
+
};
|
|
15593
|
+
}
|
|
15594
|
+
async function assertDirectoryExists(directory) {
|
|
15595
|
+
const stats = await stat3(directory);
|
|
15596
|
+
if (!stats.isDirectory()) {
|
|
15597
|
+
throw new Error(`${directory} is not a directory.`);
|
|
15598
|
+
}
|
|
15599
|
+
}
|
|
15600
|
+
async function resolveConfiguredLocalAgentRecord(agentId) {
|
|
15601
|
+
const overrides = await readRelayAgentOverrides();
|
|
15602
|
+
const override = overrides[agentId];
|
|
15603
|
+
if (override) {
|
|
15604
|
+
return localAgentRecordFromRelayAgentOverride(agentId, override);
|
|
15605
|
+
}
|
|
15606
|
+
const registry = await readLocalAgentRegistry();
|
|
15607
|
+
const record = registry[agentId];
|
|
15608
|
+
return record ? normalizeLocalAgentRecord(agentId, record) : null;
|
|
15609
|
+
}
|
|
15610
|
+
async function getLocalAgentConfig(agentId) {
|
|
15611
|
+
const record = await resolveConfiguredLocalAgentRecord(agentId);
|
|
15612
|
+
if (!record) {
|
|
15613
|
+
return null;
|
|
15614
|
+
}
|
|
15615
|
+
return buildLocalAgentConfigState(agentId, record);
|
|
15616
|
+
}
|
|
15617
|
+
function defaultLocalAgentSessionId(agentId, harness) {
|
|
15618
|
+
return normalizeTmuxSessionName2(undefined, `${agentId}-${harness}`);
|
|
15619
|
+
}
|
|
15620
|
+
async function updateLocalAgentCard(agentId, input) {
|
|
15621
|
+
const existing = await getLocalAgentConfig(agentId);
|
|
15622
|
+
if (!existing) {
|
|
15623
|
+
return null;
|
|
15624
|
+
}
|
|
15625
|
+
const nextHarness = input.harness ? normalizeLocalAgentHarness(input.harness) : existing.runtime.harness;
|
|
15626
|
+
const harnessChanged = nextHarness !== existing.runtime.harness;
|
|
15627
|
+
const model = input.model === undefined ? harnessChanged ? null : undefined : input.model;
|
|
15628
|
+
return updateLocalAgentConfig(agentId, {
|
|
15629
|
+
runtime: {
|
|
15630
|
+
cwd: existing.runtime.cwd,
|
|
15631
|
+
harness: nextHarness,
|
|
15632
|
+
transport: harnessChanged ? normalizeLocalAgentTransport(undefined, nextHarness) : existing.runtime.transport,
|
|
15633
|
+
sessionId: harnessChanged ? defaultLocalAgentSessionId(agentId, nextHarness) : existing.runtime.sessionId
|
|
15634
|
+
},
|
|
15635
|
+
systemPrompt: existing.systemPrompt,
|
|
15636
|
+
launchArgs: harnessChanged ? [] : existing.launchArgs,
|
|
15637
|
+
model,
|
|
15638
|
+
reasoningEffort: input.reasoningEffort,
|
|
15639
|
+
permissionProfile: input.permissionProfile,
|
|
15640
|
+
capabilities: existing.capabilities
|
|
15641
|
+
});
|
|
15642
|
+
}
|
|
15643
|
+
async function updateLocalAgentConfig(agentId, input) {
|
|
15644
|
+
const [registry, overrides] = await Promise.all([
|
|
15645
|
+
readLocalAgentRegistry(),
|
|
15646
|
+
readRelayAgentOverrides()
|
|
15647
|
+
]);
|
|
15648
|
+
const record = registry[agentId] ?? (overrides[agentId] ? localAgentRecordFromRelayAgentOverride(agentId, overrides[agentId]) : undefined);
|
|
15649
|
+
if (!record) {
|
|
15650
|
+
return null;
|
|
15651
|
+
}
|
|
15652
|
+
const cwd = normalizeProjectPath(input.runtime.cwd || record.cwd);
|
|
15653
|
+
await assertDirectoryExists(cwd);
|
|
15654
|
+
const nextHarness = normalizeLocalAgentHarness(input.runtime.harness);
|
|
15655
|
+
const nextTransport = normalizeLocalAgentTransport(input.runtime.transport ?? record.transport, nextHarness);
|
|
15656
|
+
let nextLaunchArgs = setLaunchModelForHarness(nextHarness, input.launchArgs, input.model);
|
|
15657
|
+
if (input.reasoningEffort !== undefined) {
|
|
15658
|
+
const stripped = stripLaunchReasoningEffortForHarness(nextHarness, nextLaunchArgs);
|
|
15659
|
+
const requestedReasoningEffort = normalizeRequestedReasoningEffort(input.reasoningEffort ?? undefined);
|
|
15660
|
+
nextLaunchArgs = requestedReasoningEffort ? [
|
|
15661
|
+
...stripped,
|
|
15662
|
+
...buildLaunchArgsForRequestedReasoningEffort(nextHarness, requestedReasoningEffort)
|
|
15663
|
+
] : stripped;
|
|
15664
|
+
}
|
|
15665
|
+
const nextPermissionProfile = input.permissionProfile === undefined ? record.permissionProfile : input.permissionProfile === null ? undefined : parseScoutPermissionProfile(input.permissionProfile);
|
|
15666
|
+
const nextRecord = normalizeLocalAgentRecord(agentId, {
|
|
15667
|
+
...record,
|
|
15668
|
+
cwd,
|
|
15669
|
+
tmuxSession: input.runtime.sessionId,
|
|
15670
|
+
harness: nextHarness,
|
|
15671
|
+
defaultHarness: nextHarness,
|
|
15672
|
+
harnessProfiles: {
|
|
15673
|
+
...record.harnessProfiles ?? {},
|
|
15674
|
+
[normalizeManagedHarness2(input.runtime.harness, "claude")]: {
|
|
15675
|
+
cwd,
|
|
15676
|
+
transport: nextTransport,
|
|
15677
|
+
sessionId: normalizeTmuxSessionName2(input.runtime.sessionId, `${agentId}-${normalizeManagedHarness2(input.runtime.harness, "claude")}`),
|
|
15678
|
+
launchArgs: nextLaunchArgs,
|
|
15679
|
+
...nextPermissionProfile ? { permissionProfile: nextPermissionProfile } : {}
|
|
15680
|
+
}
|
|
15681
|
+
},
|
|
15682
|
+
transport: nextTransport,
|
|
15683
|
+
systemPrompt: input.systemPrompt.trim() || undefined,
|
|
15684
|
+
launchArgs: nextLaunchArgs,
|
|
15685
|
+
permissionProfile: nextPermissionProfile,
|
|
15686
|
+
capabilities: input.capabilities
|
|
15687
|
+
});
|
|
15688
|
+
registry[agentId] = nextRecord;
|
|
15689
|
+
await writeLocalAgentRegistry(registry);
|
|
15690
|
+
return buildLocalAgentConfigState(agentId, nextRecord);
|
|
15691
|
+
}
|
|
15692
|
+
async function updateLocalAgentCardLifecycle(agentId, input) {
|
|
15693
|
+
const overrides = await readRelayAgentOverrides();
|
|
15694
|
+
const override = overrides[agentId];
|
|
15695
|
+
if (!override) {
|
|
15696
|
+
return null;
|
|
15697
|
+
}
|
|
15698
|
+
const lifecycle2 = normalizeLocalAgentCardLifecycle({
|
|
15699
|
+
...override.card ?? {},
|
|
15700
|
+
...input
|
|
15701
|
+
});
|
|
15702
|
+
if (!lifecycle2) {
|
|
15703
|
+
return null;
|
|
15704
|
+
}
|
|
15705
|
+
overrides[agentId] = {
|
|
15706
|
+
...override,
|
|
15707
|
+
card: lifecycle2
|
|
15708
|
+
};
|
|
15709
|
+
await writeRelayAgentOverrides(overrides);
|
|
15710
|
+
return lifecycle2;
|
|
15711
|
+
}
|
|
15712
|
+
function oneTimeCardCreatedAt(lifecycle2) {
|
|
15713
|
+
return normalizeCardTimestamp(lifecycle2.createdAt) ?? 0;
|
|
15714
|
+
}
|
|
15715
|
+
function shouldPruneOneTimeCard(lifecycle2, now, maxAgeMs) {
|
|
15716
|
+
if (lifecycle2.kind !== "one_time") {
|
|
15717
|
+
return false;
|
|
15718
|
+
}
|
|
15719
|
+
if (lifecycle2.expiresAt !== undefined && lifecycle2.expiresAt <= now) {
|
|
15720
|
+
return true;
|
|
15721
|
+
}
|
|
15722
|
+
const createdAt = oneTimeCardCreatedAt(lifecycle2);
|
|
15723
|
+
return createdAt > 0 && createdAt + maxAgeMs <= now;
|
|
15724
|
+
}
|
|
15725
|
+
function oneTimeCardMatchesScope(agentId, override, input) {
|
|
15726
|
+
if (BUILT_IN_AGENT_DEFINITION_IDS.has(agentId)) {
|
|
15727
|
+
return false;
|
|
15728
|
+
}
|
|
15729
|
+
const lifecycle2 = normalizeLocalAgentCardLifecycle(override.card);
|
|
15730
|
+
if (lifecycle2?.kind !== "one_time") {
|
|
15731
|
+
return false;
|
|
15732
|
+
}
|
|
15733
|
+
if (input.createdById?.trim() && lifecycle2.createdById !== input.createdById.trim()) {
|
|
15734
|
+
return false;
|
|
15735
|
+
}
|
|
15736
|
+
if (input.projectRoot?.trim()) {
|
|
15737
|
+
const scopedRoot = normalizeProjectPath(input.projectRoot);
|
|
15738
|
+
const cardRoot = normalizeProjectPath(override.projectRoot || override.runtime?.cwd || ".");
|
|
15739
|
+
if (cardRoot !== scopedRoot) {
|
|
15740
|
+
return false;
|
|
15741
|
+
}
|
|
15742
|
+
}
|
|
15743
|
+
return true;
|
|
15744
|
+
}
|
|
15745
|
+
async function retireLocalAgentOverrides(overrides, agentIds) {
|
|
15746
|
+
const retired = [];
|
|
15747
|
+
for (const agentId of agentIds) {
|
|
15748
|
+
const override = overrides[agentId];
|
|
15749
|
+
if (!override) {
|
|
15750
|
+
continue;
|
|
15751
|
+
}
|
|
15752
|
+
const record = localAgentRecordFromRelayAgentOverride(agentId, override);
|
|
15753
|
+
const status = localAgentStatusFromRecord(agentId, record, localAgentStatusSource(agentId, overrides));
|
|
15754
|
+
await stopLocalAgent(agentId).catch(() => null);
|
|
15755
|
+
retired.push({
|
|
15756
|
+
...status,
|
|
15757
|
+
isOnline: false
|
|
15758
|
+
});
|
|
15759
|
+
delete overrides[agentId];
|
|
15760
|
+
}
|
|
15761
|
+
if (retired.length > 0) {
|
|
15762
|
+
await writeRelayAgentOverrides(overrides);
|
|
15763
|
+
}
|
|
15764
|
+
return retired;
|
|
15765
|
+
}
|
|
15766
|
+
async function pruneOneTimeLocalAgentCards(input = {}) {
|
|
15767
|
+
const now = input.now ?? Date.now();
|
|
15768
|
+
const maxAgeMs = Math.max(0, input.maxAgeMs ?? DEFAULT_ONE_TIME_LOCAL_AGENT_CARD_TTL_MS);
|
|
15769
|
+
const maxCount = Math.max(0, input.maxCount ?? DEFAULT_ONE_TIME_LOCAL_AGENT_CARD_RETAIN);
|
|
15770
|
+
const excluded = new Set(input.excludeAgentIds ?? []);
|
|
15771
|
+
const overrides = await readRelayAgentOverrides();
|
|
15772
|
+
const candidates = Object.entries(overrides).filter(([agentId, override]) => !excluded.has(agentId) && oneTimeCardMatchesScope(agentId, override, input)).map(([agentId, override]) => ({
|
|
15773
|
+
agentId,
|
|
15774
|
+
override,
|
|
15775
|
+
lifecycle: normalizeLocalAgentCardLifecycle(override.card)
|
|
15776
|
+
})).sort((left, right) => oneTimeCardCreatedAt(right.lifecycle) - oneTimeCardCreatedAt(left.lifecycle) || left.agentId.localeCompare(right.agentId));
|
|
15777
|
+
const retireIds = new Set;
|
|
15778
|
+
for (const candidate of candidates) {
|
|
15779
|
+
if (shouldPruneOneTimeCard(candidate.lifecycle, now, maxAgeMs)) {
|
|
15780
|
+
retireIds.add(candidate.agentId);
|
|
15781
|
+
}
|
|
15782
|
+
}
|
|
15783
|
+
const retained = candidates.filter((candidate) => !retireIds.has(candidate.agentId));
|
|
15784
|
+
for (const candidate of retained.slice(maxCount)) {
|
|
15785
|
+
retireIds.add(candidate.agentId);
|
|
15786
|
+
}
|
|
15787
|
+
const retired = await retireLocalAgentOverrides({ ...overrides }, retireIds);
|
|
15788
|
+
return {
|
|
15789
|
+
inspected: candidates.length,
|
|
15790
|
+
remaining: Math.max(0, candidates.length - retired.length),
|
|
15791
|
+
retired
|
|
15792
|
+
};
|
|
15793
|
+
}
|
|
15794
|
+
async function retireLocalAgent(agentId) {
|
|
15795
|
+
const overrides = await readRelayAgentOverrides();
|
|
15796
|
+
const override = overrides[agentId];
|
|
15797
|
+
if (!override) {
|
|
15798
|
+
return null;
|
|
15799
|
+
}
|
|
15800
|
+
const record = localAgentRecordFromRelayAgentOverride(agentId, override);
|
|
15801
|
+
const status = localAgentStatusFromRecord(agentId, record, localAgentStatusSource(agentId, overrides));
|
|
15802
|
+
await stopLocalAgent(agentId).catch(() => null);
|
|
15803
|
+
const nextOverrides = { ...overrides };
|
|
15804
|
+
delete nextOverrides[agentId];
|
|
15805
|
+
await writeRelayAgentOverrides(nextOverrides);
|
|
15806
|
+
return {
|
|
15807
|
+
...status,
|
|
15808
|
+
isOnline: false
|
|
15809
|
+
};
|
|
15810
|
+
}
|
|
15279
15811
|
function buildCodexAgentSessionOptions(agentName, record, systemPrompt) {
|
|
15280
15812
|
const permissionPosture = compileCodexPermissionProfile(record.permissionProfile);
|
|
15281
15813
|
return {
|
|
@@ -15326,6 +15858,90 @@ function buildLocalAgentSystemPrompt(agentName, projectName, projectPath, option
|
|
|
15326
15858
|
function buildLocalAgentInitialMessage(projectName, agentName) {
|
|
15327
15859
|
return `You are now online as the ${agentName} relay agent for ${projectName}. Announce yourself on the relay with: ${brokerRelayCommand()} send --as ${agentName} "relay agent online \u2014 ready to assist with ${projectName}"`;
|
|
15328
15860
|
}
|
|
15861
|
+
function tmuxDispatchSleep(ms) {
|
|
15862
|
+
return new Promise((resolve9) => setTimeout(resolve9, ms));
|
|
15863
|
+
}
|
|
15864
|
+
function captureTmuxPaneTail(sessionName, lines) {
|
|
15865
|
+
try {
|
|
15866
|
+
return execFileSync4("tmux", ["capture-pane", "-p", "-t", sessionName, "-S", `-${lines}`, "-E", "-"], { stdio: ["ignore", "pipe", "pipe"], encoding: "utf8" });
|
|
15867
|
+
} catch {
|
|
15868
|
+
return "";
|
|
15869
|
+
}
|
|
15870
|
+
}
|
|
15871
|
+
async function waitForTmuxHarnessReady(sessionName, harness) {
|
|
15872
|
+
if (harness !== "claude") {
|
|
15873
|
+
return;
|
|
15874
|
+
}
|
|
15875
|
+
const deadline = Date.now() + TMUX_READY_TIMEOUT_MS;
|
|
15876
|
+
let paneTail = "";
|
|
15877
|
+
while (Date.now() < deadline) {
|
|
15878
|
+
if (!isLocalAgentSessionAlive(sessionName)) {
|
|
15879
|
+
throw new Error(`tmux session ${sessionName} exited before Claude Code was ready.`);
|
|
15880
|
+
}
|
|
15881
|
+
paneTail = captureTmuxPaneTail(sessionName, TMUX_READY_TAIL_LINES);
|
|
15882
|
+
if (tmuxPaneTailShowsReadyComposer(paneTail)) {
|
|
15883
|
+
return;
|
|
15884
|
+
}
|
|
15885
|
+
await tmuxDispatchSleep(TMUX_READY_POLL_MS);
|
|
15886
|
+
}
|
|
15887
|
+
const tail = stripTerminalControlSequences(paneTail).trim().split(/\r?\n/).slice(-20).join(`
|
|
15888
|
+
`).trim();
|
|
15889
|
+
throw new Error(`tmux session ${sessionName} did not show a ready Claude Code composer within ${TMUX_READY_TIMEOUT_MS}ms.` + (tail ? `
|
|
15890
|
+
Recent pane tail:
|
|
15891
|
+
${tail}` : ""));
|
|
15892
|
+
}
|
|
15893
|
+
function tmuxPaneTailShowsReadyComposer(paneTail) {
|
|
15894
|
+
const cleanedTail = stripTerminalControlSequences(paneTail);
|
|
15895
|
+
const lines = cleanedTail.split(/\r?\n/);
|
|
15896
|
+
const anchor = findActiveTmuxComposerAnchor(lines);
|
|
15897
|
+
if (!anchor) {
|
|
15898
|
+
return false;
|
|
15899
|
+
}
|
|
15900
|
+
const afterComposerLines = [];
|
|
15901
|
+
for (const line of lines.slice(anchor.index + 1)) {
|
|
15902
|
+
if (isTmuxComposerBoundary(line)) {
|
|
15903
|
+
break;
|
|
15904
|
+
}
|
|
15905
|
+
afterComposerLines.push(line);
|
|
15906
|
+
}
|
|
15907
|
+
return !tmuxPaneTailShowsHarnessActivity(afterComposerLines.join(`
|
|
15908
|
+
`));
|
|
15909
|
+
}
|
|
15910
|
+
function stripTerminalControlSequences(value) {
|
|
15911
|
+
return value.replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "");
|
|
15912
|
+
}
|
|
15913
|
+
function findActiveTmuxComposerAnchor(lines) {
|
|
15914
|
+
const inlineComposerIndex = findLastIndex(lines, (line) => /^\s*[\u276F\u203A]\s*/.test(line));
|
|
15915
|
+
const boxedComposerIndex = findLastIndex(lines, (line) => /^\s*[\u2502\u2503]\s*[>\u276F]\s*/.test(line));
|
|
15916
|
+
if (inlineComposerIndex < 0 && boxedComposerIndex < 0) {
|
|
15917
|
+
return null;
|
|
15918
|
+
}
|
|
15919
|
+
if (inlineComposerIndex > boxedComposerIndex) {
|
|
15920
|
+
return { index: inlineComposerIndex, kind: "inline" };
|
|
15921
|
+
}
|
|
15922
|
+
return { index: boxedComposerIndex, kind: "boxed" };
|
|
15923
|
+
}
|
|
15924
|
+
function findLastIndex(items, predicate) {
|
|
15925
|
+
for (let index = items.length - 1;index >= 0; index -= 1) {
|
|
15926
|
+
if (predicate(items[index])) {
|
|
15927
|
+
return index;
|
|
15928
|
+
}
|
|
15929
|
+
}
|
|
15930
|
+
return -1;
|
|
15931
|
+
}
|
|
15932
|
+
function isTmuxComposerBoundary(line) {
|
|
15933
|
+
const trimmed = line.trim();
|
|
15934
|
+
if (!trimmed) {
|
|
15935
|
+
return false;
|
|
15936
|
+
}
|
|
15937
|
+
if (/^[\u2500\u2501\u2550\u256D\u256E\u2570\u256F\u250C\u2510\u2514\u2518\u2554\u2557\u255A\u255D\u255F\u2562\u2560\u2563\u256A\u256B\u256C\u2569\u2566\u2564\u2567\u254C\u254D\u254E\u254F\s]+$/.test(trimmed)) {
|
|
15938
|
+
return true;
|
|
15939
|
+
}
|
|
15940
|
+
return /^--\s*(?:INSERT|NORMAL)\s*--/.test(trimmed) || /^(?:Opus|Sonnet|Haiku|Claude|Codex|GPT)\b/.test(trimmed);
|
|
15941
|
+
}
|
|
15942
|
+
function tmuxPaneTailShowsHarnessActivity(paneTail) {
|
|
15943
|
+
return /(?:^|\n)\s*(?:[\u23FA\u25CF\u273D\u2722\u273B\u23BF]|Bash\(|Read\(|Edit\(|Write\(|Grep\(|Glob\(|TodoWrite\()/.test(paneTail);
|
|
15944
|
+
}
|
|
15329
15945
|
function shellQuoteArguments(args) {
|
|
15330
15946
|
return args.map((arg) => JSON.stringify(arg)).join(" ");
|
|
15331
15947
|
}
|
|
@@ -15336,10 +15952,10 @@ function buildLocalAgentLaunchCommand(agentName, record, projectPath, promptFile
|
|
|
15336
15952
|
const harness = normalizeLocalAgentHarness(record.harness);
|
|
15337
15953
|
const extraArgs = shellQuoteArguments(harness === "claude" ? normalizeClaudeRuntimeLaunchArgs(record.launchArgs) : normalizeLaunchArgsForHarness(harness, record.launchArgs));
|
|
15338
15954
|
if (harness === "codex") {
|
|
15339
|
-
return `exec bash ${JSON.stringify(workerScript ??
|
|
15955
|
+
return `exec bash ${JSON.stringify(workerScript ?? join16(relayAgentRuntimeDirectory(agentName), "codex-worker.sh"))}`;
|
|
15340
15956
|
}
|
|
15341
15957
|
if (harness === "pi") {
|
|
15342
|
-
const sessionDir =
|
|
15958
|
+
const sessionDir = join16(relayAgentRuntimeDirectory(agentName), "pi-sessions");
|
|
15343
15959
|
return [
|
|
15344
15960
|
"pi",
|
|
15345
15961
|
`--append-system-prompt "$(cat ${JSON.stringify(promptFile)})"`,
|
|
@@ -15409,7 +16025,7 @@ async function ensureLocalAgentOnline(agentName, record) {
|
|
|
15409
16025
|
await mkdir6(agentRuntimeDir, { recursive: true });
|
|
15410
16026
|
await mkdir6(logsDir, { recursive: true });
|
|
15411
16027
|
if (normalizedRecord.transport === "codex_app_server") {
|
|
15412
|
-
await writeFile6(
|
|
16028
|
+
await writeFile6(join16(agentRuntimeDir, "prompt.txt"), systemPrompt);
|
|
15413
16029
|
await ensureCodexAppServerAgentOnline(buildCodexAgentSessionOptions(agentName, normalizedRecord, systemPrompt));
|
|
15414
16030
|
const registry2 = await readLocalAgentRegistry();
|
|
15415
16031
|
registry2[agentName] = {
|
|
@@ -15421,7 +16037,7 @@ async function ensureLocalAgentOnline(agentName, record) {
|
|
|
15421
16037
|
return registry2[agentName];
|
|
15422
16038
|
}
|
|
15423
16039
|
if (normalizedRecord.transport === "claude_stream_json") {
|
|
15424
|
-
await writeFile6(
|
|
16040
|
+
await writeFile6(join16(agentRuntimeDir, "prompt.txt"), systemPrompt);
|
|
15425
16041
|
await ensureClaudeStreamJsonAgentOnline(buildClaudeAgentSessionOptions(agentName, normalizedRecord, systemPrompt));
|
|
15426
16042
|
const registry2 = await readLocalAgentRegistry();
|
|
15427
16043
|
registry2[agentName] = {
|
|
@@ -15434,17 +16050,17 @@ async function ensureLocalAgentOnline(agentName, record) {
|
|
|
15434
16050
|
}
|
|
15435
16051
|
const initialMessage = buildLocalAgentInitialMessage(projectName, agentName);
|
|
15436
16052
|
const bootstrapPrompt = buildLocalAgentBootstrapPrompt(normalizeLocalAgentHarness(normalizedRecord.harness), systemPrompt, initialMessage);
|
|
15437
|
-
const queueDirectory =
|
|
15438
|
-
const processingDirectory =
|
|
15439
|
-
const processedDirectory =
|
|
15440
|
-
const promptFile =
|
|
15441
|
-
const initialFile =
|
|
15442
|
-
const launchScript =
|
|
15443
|
-
const workerScript =
|
|
15444
|
-
const codexSessionIdFile =
|
|
15445
|
-
const stateFile =
|
|
15446
|
-
const stdoutLogFile =
|
|
15447
|
-
const stderrLogFile =
|
|
16053
|
+
const queueDirectory = join16(agentRuntimeDir, "queue");
|
|
16054
|
+
const processingDirectory = join16(queueDirectory, "processing");
|
|
16055
|
+
const processedDirectory = join16(queueDirectory, "processed");
|
|
16056
|
+
const promptFile = join16(agentRuntimeDir, "prompt.txt");
|
|
16057
|
+
const initialFile = join16(agentRuntimeDir, "initial.txt");
|
|
16058
|
+
const launchScript = join16(agentRuntimeDir, "launch.sh");
|
|
16059
|
+
const workerScript = join16(agentRuntimeDir, "codex-worker.sh");
|
|
16060
|
+
const codexSessionIdFile = join16(agentRuntimeDir, "codex-session-id.txt");
|
|
16061
|
+
const stateFile = join16(agentRuntimeDir, "state.json");
|
|
16062
|
+
const stdoutLogFile = join16(logsDir, "stdout.log");
|
|
16063
|
+
const stderrLogFile = join16(logsDir, "stderr.log");
|
|
15448
16064
|
await writeFile6(promptFile, systemPrompt);
|
|
15449
16065
|
await writeFile6(initialFile, bootstrapPrompt);
|
|
15450
16066
|
await writeFile6(stderrLogFile, "");
|
|
@@ -15509,11 +16125,17 @@ async function ensureLocalAgentOnline(agentName, record) {
|
|
|
15509
16125
|
await new Promise((resolve9) => setTimeout(resolve9, 100));
|
|
15510
16126
|
}
|
|
15511
16127
|
if (!isLocalAgentSessionAlive(normalizedRecord.tmuxSession)) {
|
|
15512
|
-
const stderrTail =
|
|
16128
|
+
const stderrTail = existsSync12(stderrLogFile) ? readFileSync7(stderrLogFile, "utf8").trim().split(/\r?\n/).slice(-10).join(`
|
|
15513
16129
|
`).trim() : "";
|
|
15514
16130
|
throw new Error(stderrTail ? `Relay agent ${agentName} failed to stay online:
|
|
15515
16131
|
${stderrTail}` : `Relay agent ${agentName} failed to stay online.`);
|
|
15516
16132
|
}
|
|
16133
|
+
try {
|
|
16134
|
+
await waitForTmuxHarnessReady(normalizedRecord.tmuxSession, normalizeLocalAgentHarness(normalizedRecord.harness));
|
|
16135
|
+
} catch (error) {
|
|
16136
|
+
killAgentSession(normalizedRecord.tmuxSession);
|
|
16137
|
+
throw error;
|
|
16138
|
+
}
|
|
15517
16139
|
const registry = await readLocalAgentRegistry();
|
|
15518
16140
|
registry[agentName] = {
|
|
15519
16141
|
...normalizedRecord,
|
|
@@ -15695,6 +16317,7 @@ async function startLocalAgent(input) {
|
|
|
15695
16317
|
const effectiveCwd = input.cwdOverride ? normalizeProjectPath(input.cwdOverride) : undefined;
|
|
15696
16318
|
const shouldEnsureOnline = input.ensureOnline !== false;
|
|
15697
16319
|
const requestedPermissionProfile = parseScoutPermissionProfile(input.permissionProfile);
|
|
16320
|
+
const cardLifecycle = normalizeLocalAgentCardLifecycle(input.card);
|
|
15698
16321
|
const requestedDefinitionId = input.agentName?.trim() ? normalizeAgentSelectorSegment(input.agentName.trim()) : "";
|
|
15699
16322
|
if (input.agentName?.trim() && !requestedDefinitionId) {
|
|
15700
16323
|
throw new Error(`Invalid agent name "${input.agentName}".`);
|
|
@@ -15744,7 +16367,8 @@ async function startLocalAgent(input) {
|
|
|
15744
16367
|
const configDefinitionId = coldProjectConfig?.agent?.id?.trim() ? normalizeAgentSelectorSegment(coldProjectConfig.agent.id.trim()) : "";
|
|
15745
16368
|
const definitionId = requestedDefinitionId || configDefinitionId || normalizeAgentSelectorSegment(basename7(projectRoot)) || "agent";
|
|
15746
16369
|
const configDisplayName = coldProjectConfig?.agent?.displayName?.trim() || "";
|
|
15747
|
-
const
|
|
16370
|
+
const operatorAugmentDefaults = operatorAugmentDefaultsForDefinitionId(definitionId);
|
|
16371
|
+
const effectiveDisplayName = input.displayName || operatorAugmentDefaults?.displayName || configDisplayName || titleCaseLocalAgentName(definitionId);
|
|
15748
16372
|
const instance = buildRelayAgentInstance(definitionId, projectRoot);
|
|
15749
16373
|
const configDefaultHarness = coldProjectConfig?.agent?.runtime?.defaultHarness;
|
|
15750
16374
|
const effectiveHarness = normalizeManagedHarness2(preferredHarness ?? configDefaultHarness, "claude");
|
|
@@ -15767,8 +16391,10 @@ async function startLocalAgent(input) {
|
|
|
15767
16391
|
projectConfigPath: coldProjectConfigPath,
|
|
15768
16392
|
source: "manual",
|
|
15769
16393
|
startedAt: nowSeconds2(),
|
|
16394
|
+
...operatorAugmentDefaults ? { systemPrompt: operatorAugmentDefaults.systemPrompt } : {},
|
|
15770
16395
|
launchArgs,
|
|
15771
16396
|
defaultHarness: effectiveHarness,
|
|
16397
|
+
...cardLifecycle ? { card: cardLifecycle } : {},
|
|
15772
16398
|
harnessProfiles: {
|
|
15773
16399
|
[effectiveHarness]: {
|
|
15774
16400
|
cwd: effectiveCwd ?? projectRoot,
|
|
@@ -15804,18 +16430,21 @@ async function startLocalAgent(input) {
|
|
|
15804
16430
|
reasoningEffort: input.reasoningEffort
|
|
15805
16431
|
});
|
|
15806
16432
|
const nextTransport = normalizeLocalAgentTransport(preferredHarness ? undefined : matchingOverride.runtime?.transport, nextHarness);
|
|
16433
|
+
const operatorAugmentDefaults = operatorAugmentDefaultsForDefinitionId(requestedDefinitionId);
|
|
15807
16434
|
overrides[instance.id] = {
|
|
15808
16435
|
agentId: instance.id,
|
|
15809
16436
|
definitionId: requestedDefinitionId,
|
|
15810
|
-
displayName: input.displayName || titleCaseLocalAgentName(requestedDefinitionId),
|
|
16437
|
+
displayName: input.displayName || operatorAugmentDefaults?.displayName || titleCaseLocalAgentName(requestedDefinitionId),
|
|
15811
16438
|
projectName: matchingOverride.projectName ?? basename7(matchingProjectRoot),
|
|
15812
16439
|
projectRoot: matchingProjectRoot,
|
|
15813
16440
|
projectConfigPath: null,
|
|
15814
16441
|
source: "manual",
|
|
15815
16442
|
startedAt: matchingOverride.startedAt ?? nowSeconds2(),
|
|
16443
|
+
...operatorAugmentDefaults ? { systemPrompt: operatorAugmentDefaults.systemPrompt } : {},
|
|
15816
16444
|
launchArgs: nextHarness === nextDefaultHarness ? nextLaunchArgs : matchingOverride.launchArgs,
|
|
15817
16445
|
capabilities: matchingOverride.capabilities,
|
|
15818
16446
|
defaultHarness: nextDefaultHarness,
|
|
16447
|
+
...cardLifecycle ? { card: cardLifecycle } : {},
|
|
15819
16448
|
harnessProfiles: {
|
|
15820
16449
|
...matchingOverride.harnessProfiles ?? {},
|
|
15821
16450
|
[nextHarness]: {
|
|
@@ -15837,7 +16466,9 @@ async function startLocalAgent(input) {
|
|
|
15837
16466
|
await writeRelayAgentOverrides(overrides);
|
|
15838
16467
|
targetAgentId = instance.id;
|
|
15839
16468
|
} else {
|
|
15840
|
-
|
|
16469
|
+
const operatorAugmentDefaults = operatorAugmentDefaultsForDefinitionId(matchingOverride.definitionId ?? requestedDefinitionId);
|
|
16470
|
+
const shouldApplyOperatorAugmentPrompt = Boolean(operatorAugmentDefaults && !matchingOverride.systemPrompt?.trim());
|
|
16471
|
+
if (input.model || input.reasoningEffort || requestedPermissionProfile || cardLifecycle || shouldApplyOperatorAugmentPrompt) {
|
|
15841
16472
|
const existingHarness = normalizeManagedHarness2(preferredHarness ?? matchingOverride.defaultHarness ?? matchingOverride.runtime?.harness, "claude");
|
|
15842
16473
|
const nextLaunchArgs = applyRequestedRuntimeOptionsToLaunchArgs(existingHarness, launchArgsForOverrideHarness(matchingOverride, existingHarness), {
|
|
15843
16474
|
model: input.model,
|
|
@@ -15845,6 +16476,8 @@ async function startLocalAgent(input) {
|
|
|
15845
16476
|
});
|
|
15846
16477
|
overrides[matchingAgentId] = {
|
|
15847
16478
|
...matchingOverride,
|
|
16479
|
+
...cardLifecycle ? { card: cardLifecycle } : {},
|
|
16480
|
+
...shouldApplyOperatorAugmentPrompt ? { systemPrompt: operatorAugmentDefaults.systemPrompt } : {},
|
|
15848
16481
|
launchArgs: existingHarness === defaultHarnessForOverride(matchingOverride, existingHarness) ? nextLaunchArgs : matchingOverride.launchArgs,
|
|
15849
16482
|
harnessProfiles: {
|
|
15850
16483
|
...matchingOverride.harnessProfiles ?? {},
|
|
@@ -15949,9 +16582,9 @@ async function restartAllLocalAgents(options = {}) {
|
|
|
15949
16582
|
function readPersistedClaudeSessionId(agentName) {
|
|
15950
16583
|
try {
|
|
15951
16584
|
const runtimeDir = relayAgentRuntimeDirectory(agentName);
|
|
15952
|
-
const catalogPath =
|
|
15953
|
-
if (
|
|
15954
|
-
const raw =
|
|
16585
|
+
const catalogPath = join16(runtimeDir, "session-catalog.json");
|
|
16586
|
+
if (existsSync12(catalogPath)) {
|
|
16587
|
+
const raw = readFileSync7(catalogPath, "utf8").trim();
|
|
15955
16588
|
if (raw) {
|
|
15956
16589
|
const catalog = JSON.parse(raw);
|
|
15957
16590
|
if (typeof catalog.activeSessionId === "string" && catalog.activeSessionId.trim()) {
|
|
@@ -15959,9 +16592,9 @@ function readPersistedClaudeSessionId(agentName) {
|
|
|
15959
16592
|
}
|
|
15960
16593
|
}
|
|
15961
16594
|
}
|
|
15962
|
-
const legacyPath =
|
|
15963
|
-
if (
|
|
15964
|
-
const value =
|
|
16595
|
+
const legacyPath = join16(runtimeDir, "claude-session-id.txt");
|
|
16596
|
+
if (existsSync12(legacyPath)) {
|
|
16597
|
+
const value = readFileSync7(legacyPath, "utf8").trim();
|
|
15965
16598
|
return value || null;
|
|
15966
16599
|
}
|
|
15967
16600
|
return null;
|
|
@@ -15973,6 +16606,7 @@ function buildLocalAgentBinding(agentId, record, alive, nodeId, source) {
|
|
|
15973
16606
|
const normalizedRecord = normalizeLocalAgentRecord(agentId, record);
|
|
15974
16607
|
const configuredModel = readLaunchModelForHarness(normalizeLocalAgentHarness(normalizedRecord.harness), normalizedRecord.launchArgs);
|
|
15975
16608
|
const codexPermissionPosture = normalizeLocalAgentHarness(normalizedRecord.harness) === "codex" ? compileCodexPermissionProfile(normalizedRecord.permissionProfile) : null;
|
|
16609
|
+
const cardLifecycle = normalizeLocalAgentCardLifecycle(normalizedRecord.card);
|
|
15976
16610
|
const definitionId = normalizedRecord.definitionId ?? agentId;
|
|
15977
16611
|
const displayName = titleCaseLocalAgentName(definitionId);
|
|
15978
16612
|
const projectRoot = normalizedRecord.projectRoot ?? normalizedRecord.cwd;
|
|
@@ -16000,6 +16634,7 @@ function buildLocalAgentBinding(agentId, record, alive, nodeId, source) {
|
|
|
16000
16634
|
workspaceQualifier: instance.workspaceQualifier,
|
|
16001
16635
|
branch: instance.branch,
|
|
16002
16636
|
...configuredModel ? { model: configuredModel } : {},
|
|
16637
|
+
...cardLifecycle ? { cardLifecycle } : {},
|
|
16003
16638
|
...codexPermissionPosture ? {
|
|
16004
16639
|
permissionProfile: codexPermissionPosture.profile,
|
|
16005
16640
|
approvalPolicy: codexPermissionPosture.approvalPolicy,
|
|
@@ -16035,6 +16670,7 @@ function buildLocalAgentBinding(agentId, record, alive, nodeId, source) {
|
|
|
16035
16670
|
workspaceQualifier: instance.workspaceQualifier,
|
|
16036
16671
|
branch: instance.branch,
|
|
16037
16672
|
...configuredModel ? { model: configuredModel } : {},
|
|
16673
|
+
...cardLifecycle ? { cardLifecycle } : {},
|
|
16038
16674
|
...codexPermissionPosture ? {
|
|
16039
16675
|
permissionProfile: codexPermissionPosture.profile,
|
|
16040
16676
|
approvalPolicy: codexPermissionPosture.approvalPolicy,
|
|
@@ -16075,6 +16711,7 @@ function buildLocalAgentBinding(agentId, record, alive, nodeId, source) {
|
|
|
16075
16711
|
workspaceQualifier: instance.workspaceQualifier,
|
|
16076
16712
|
branch: instance.branch,
|
|
16077
16713
|
...configuredModel ? { model: configuredModel } : {},
|
|
16714
|
+
...cardLifecycle ? { cardLifecycle } : {},
|
|
16078
16715
|
...codexPermissionPosture ? {
|
|
16079
16716
|
permissionProfile: codexPermissionPosture.profile,
|
|
16080
16717
|
approvalPolicy: codexPermissionPosture.approvalPolicy,
|
|
@@ -16161,9 +16798,10 @@ async function ensureLocalAgentBindingOnline(agentId, nodeId, options = {}) {
|
|
|
16161
16798
|
const onlineRecord = await ensureLocalAgentOnline(agentId, recordForHarness(localAgentRecordFromRelayAgentOverride(agentId, override), options.harness));
|
|
16162
16799
|
return buildLocalAgentBinding(agentId, onlineRecord, isLocalAgentRecordOnline(agentId, onlineRecord), nodeId, "relay-agent-registry");
|
|
16163
16800
|
}
|
|
16164
|
-
var MODULE_DIRECTORY, OPENSCOUT_REPO_ROOT, DEFAULT_LOCAL_AGENT_CAPABILITIES, DEFAULT_LOCAL_AGENT_HARNESS = "claude", SUPPORTED_LOCAL_AGENT_HARNESSES, SUPPORTED_SCOUT_HARNESSES, DEFAULT_CLAUDE_SCOUT_ALLOWED_TOOLS;
|
|
16801
|
+
var MODULE_DIRECTORY, OPENSCOUT_REPO_ROOT, DEFAULT_LOCAL_AGENT_CAPABILITIES, DEFAULT_LOCAL_AGENT_HARNESS = "claude", DEFAULT_ONE_TIME_LOCAL_AGENT_CARD_TTL_MS, DEFAULT_ONE_TIME_LOCAL_AGENT_CARD_RETAIN = 24, SUPPORTED_LOCAL_AGENT_HARNESSES, SUPPORTED_SCOUT_HARNESSES, DEFAULT_CLAUDE_SCOUT_ALLOWED_TOOLS, TMUX_READY_TIMEOUT_MS = 20000, TMUX_READY_POLL_MS = 250, TMUX_READY_TAIL_LINES = 80;
|
|
16165
16802
|
var init_local_agents = __esm(() => {
|
|
16166
16803
|
init_src();
|
|
16804
|
+
init_dispatch_stalled();
|
|
16167
16805
|
init_claude_stream_json();
|
|
16168
16806
|
init_codex_app_server();
|
|
16169
16807
|
init_setup();
|
|
@@ -16173,9 +16811,11 @@ var init_local_agents = __esm(() => {
|
|
|
16173
16811
|
init_local_agent_template();
|
|
16174
16812
|
init_permission_policy2();
|
|
16175
16813
|
init_requester_timeout();
|
|
16176
|
-
|
|
16814
|
+
init_user_config();
|
|
16815
|
+
MODULE_DIRECTORY = dirname9(fileURLToPath6(import.meta.url));
|
|
16177
16816
|
OPENSCOUT_REPO_ROOT = resolve8(MODULE_DIRECTORY, "..", "..", "..");
|
|
16178
16817
|
DEFAULT_LOCAL_AGENT_CAPABILITIES = ["chat", "invoke", "deliver"];
|
|
16818
|
+
DEFAULT_ONE_TIME_LOCAL_AGENT_CARD_TTL_MS = 24 * 60 * 60 * 1000;
|
|
16179
16819
|
SUPPORTED_LOCAL_AGENT_HARNESSES = ["claude", "codex", "pi"];
|
|
16180
16820
|
SUPPORTED_SCOUT_HARNESSES = [
|
|
16181
16821
|
...SUPPORTED_LOCAL_AGENT_HARNESSES,
|
|
@@ -16190,8 +16830,8 @@ var init_local_agents = __esm(() => {
|
|
|
16190
16830
|
"mcp__scout__agents_search",
|
|
16191
16831
|
"mcp__scout__agents_resolve",
|
|
16192
16832
|
"mcp__scout__messages_reply",
|
|
16833
|
+
"mcp__scout__ask",
|
|
16193
16834
|
"mcp__scout__messages_send",
|
|
16194
|
-
"mcp__scout__invocations_ask",
|
|
16195
16835
|
"mcp__scout__invocations_get",
|
|
16196
16836
|
"mcp__scout__invocations_wait",
|
|
16197
16837
|
"mcp__scout__work_update",
|
|
@@ -16214,6 +16854,9 @@ function scoutBrokerInvocationPath(invocationId) {
|
|
|
16214
16854
|
function scoutBrokerInvocationStreamPath(invocationId) {
|
|
16215
16855
|
return `${scoutBrokerInvocationPath(invocationId)}/stream`;
|
|
16216
16856
|
}
|
|
16857
|
+
function scoutBrokerInvocationLifecyclePath(invocationId) {
|
|
16858
|
+
return `${scoutBrokerInvocationPath(invocationId)}/lifecycle`;
|
|
16859
|
+
}
|
|
16217
16860
|
var scoutBrokerPaths, openAiAudioSpeechUrl = "https://api.openai.com/v1/audio/speech";
|
|
16218
16861
|
var init_paths = __esm(() => {
|
|
16219
16862
|
scoutBrokerPaths = {
|
|
@@ -16256,35 +16899,6 @@ function buildScoutAskMetadata(input) {
|
|
|
16256
16899
|
};
|
|
16257
16900
|
}
|
|
16258
16901
|
|
|
16259
|
-
// ../runtime/src/user-config.ts
|
|
16260
|
-
import { existsSync as existsSync12, readFileSync as readFileSync7, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "fs";
|
|
16261
|
-
import { homedir as homedir12 } from "os";
|
|
16262
|
-
import { dirname as dirname9, join as join16 } from "path";
|
|
16263
|
-
function userConfigPath() {
|
|
16264
|
-
return join16(process.env.OPENSCOUT_HOME ?? join16(homedir12(), ".openscout"), "user.json");
|
|
16265
|
-
}
|
|
16266
|
-
function loadUserConfig() {
|
|
16267
|
-
const configPath = userConfigPath();
|
|
16268
|
-
if (!existsSync12(configPath))
|
|
16269
|
-
return {};
|
|
16270
|
-
try {
|
|
16271
|
-
return JSON.parse(readFileSync7(configPath, "utf8"));
|
|
16272
|
-
} catch {
|
|
16273
|
-
return {};
|
|
16274
|
-
}
|
|
16275
|
-
}
|
|
16276
|
-
function saveUserConfig(config) {
|
|
16277
|
-
const configPath = userConfigPath();
|
|
16278
|
-
mkdirSync3(dirname9(configPath), { recursive: true });
|
|
16279
|
-
writeFileSync3(configPath, JSON.stringify(config, null, 2) + `
|
|
16280
|
-
`, "utf8");
|
|
16281
|
-
}
|
|
16282
|
-
function resolveOperatorName() {
|
|
16283
|
-
const config = loadUserConfig();
|
|
16284
|
-
return config.name?.trim() || process.env.OPENSCOUT_OPERATOR_NAME?.trim() || process.env.USER?.trim() || "operator";
|
|
16285
|
-
}
|
|
16286
|
-
var init_user_config = () => {};
|
|
16287
|
-
|
|
16288
16902
|
// ../../apps/desktop/src/core/broker/sender.ts
|
|
16289
16903
|
import { basename as basename8 } from "path";
|
|
16290
16904
|
function resolveScoutAgentName(agentName) {
|
|
@@ -16449,7 +17063,7 @@ function buildScoutReturnAddress2(snapshot, actorId, options = {}) {
|
|
|
16449
17063
|
replyToMessageId: options.replyToMessageId,
|
|
16450
17064
|
nodeId: endpoint?.nodeId || agent?.authorityNodeId || agent?.homeNodeId,
|
|
16451
17065
|
projectRoot,
|
|
16452
|
-
sessionId: endpoint?.sessionId
|
|
17066
|
+
sessionId: options.sessionId ?? endpoint?.sessionId
|
|
16453
17067
|
});
|
|
16454
17068
|
}
|
|
16455
17069
|
function sanitizeConversationSegment(value) {
|
|
@@ -16562,11 +17176,7 @@ function isSupersededBrokerAgent(snapshot, agentId) {
|
|
|
16562
17176
|
if (!agent) {
|
|
16563
17177
|
return false;
|
|
16564
17178
|
}
|
|
16565
|
-
|
|
16566
|
-
return false;
|
|
16567
|
-
}
|
|
16568
|
-
const replacementAgentId = metadataString2(agent.metadata, "replacedByAgentId");
|
|
16569
|
-
return Boolean(replacementAgentId && snapshot.agents[replacementAgentId]);
|
|
17179
|
+
return metadataBoolean(agent.metadata, "retiredFromFleet") || metadataBoolean(agent.metadata, "staleLocalRegistration");
|
|
16570
17180
|
}
|
|
16571
17181
|
function isBuiltInBrokerAgent(snapshot, agentId) {
|
|
16572
17182
|
const agent = snapshot.agents[agentId];
|
|
@@ -16677,6 +17287,17 @@ async function readScoutBrokerHealth(baseUrl = resolveScoutBrokerUrl()) {
|
|
|
16677
17287
|
nodes: health.counts.nodes ?? 0,
|
|
16678
17288
|
actors: health.counts.actors ?? 0,
|
|
16679
17289
|
agents: health.counts.agents ?? 0,
|
|
17290
|
+
agentRecords: health.counts.agentRecords,
|
|
17291
|
+
rawAgentRecords: health.counts.rawAgentRecords,
|
|
17292
|
+
configuredAgents: health.counts.configuredAgents,
|
|
17293
|
+
scoutManagedAgents: health.counts.scoutManagedAgents,
|
|
17294
|
+
currentAgentRegistrations: health.counts.currentAgentRegistrations,
|
|
17295
|
+
localAgentRegistrations: health.counts.localAgentRegistrations,
|
|
17296
|
+
remoteAgentRegistrations: health.counts.remoteAgentRegistrations,
|
|
17297
|
+
staleAgentRegistrations: health.counts.staleAgentRegistrations,
|
|
17298
|
+
retiredAgentRegistrations: health.counts.retiredAgentRegistrations,
|
|
17299
|
+
oneTimeAgentCards: health.counts.oneTimeAgentCards,
|
|
17300
|
+
persistentAgentCards: health.counts.persistentAgentCards,
|
|
16680
17301
|
conversations: health.counts.conversations ?? 0,
|
|
16681
17302
|
messages: health.counts.messages ?? 0,
|
|
16682
17303
|
flights: health.counts.flights ?? 0,
|
|
@@ -17134,7 +17755,7 @@ async function resolveMentionTargets(snapshot, text, currentDirectory) {
|
|
|
17134
17755
|
const ambiguous = [];
|
|
17135
17756
|
const candidateMap = new Map;
|
|
17136
17757
|
const endpointBackedAgentIds = [
|
|
17137
|
-
...new Set(Object.values(snapshot.endpoints).map((endpoint) => endpoint.agentId).filter((agentId) => agentId && agentId !== OPERATOR_ID))
|
|
17758
|
+
...new Set(Object.values(snapshot.endpoints).map((endpoint) => endpoint.agentId).filter((agentId) => agentId && agentId !== OPERATOR_ID && !isSupersededBrokerAgent(snapshot, agentId)))
|
|
17138
17759
|
];
|
|
17139
17760
|
for (const agent of Object.values(snapshot.agents)) {
|
|
17140
17761
|
if (isSupersededBrokerAgent(snapshot, agent.id)) {
|
|
@@ -17306,6 +17927,48 @@ async function registerScoutLocalAgentBinding(input) {
|
|
|
17306
17927
|
brokerRegistered: Boolean(broker)
|
|
17307
17928
|
};
|
|
17308
17929
|
}
|
|
17930
|
+
async function retireScoutLocalAgentBinding(input) {
|
|
17931
|
+
const broker = input.broker ?? await loadScoutBrokerContext();
|
|
17932
|
+
if (!broker) {
|
|
17933
|
+
return false;
|
|
17934
|
+
}
|
|
17935
|
+
const retiredAt = Date.now();
|
|
17936
|
+
let retired = false;
|
|
17937
|
+
const agent = broker.snapshot.agents[input.agentId];
|
|
17938
|
+
if (agent) {
|
|
17939
|
+
const nextAgent = {
|
|
17940
|
+
...agent,
|
|
17941
|
+
metadata: {
|
|
17942
|
+
...agent.metadata ?? {},
|
|
17943
|
+
retiredFromFleet: true,
|
|
17944
|
+
retiredAt
|
|
17945
|
+
}
|
|
17946
|
+
};
|
|
17947
|
+
await brokerPostJson(broker.baseUrl, scoutBrokerPaths.v1.agents, nextAgent);
|
|
17948
|
+
broker.snapshot.agents[input.agentId] = nextAgent;
|
|
17949
|
+
retired = true;
|
|
17950
|
+
}
|
|
17951
|
+
for (const endpoint of Object.values(broker.snapshot.endpoints)) {
|
|
17952
|
+
if (endpoint.agentId !== input.agentId) {
|
|
17953
|
+
continue;
|
|
17954
|
+
}
|
|
17955
|
+
const nextEndpoint = {
|
|
17956
|
+
...endpoint,
|
|
17957
|
+
state: "offline",
|
|
17958
|
+
metadata: {
|
|
17959
|
+
...endpoint.metadata ?? {},
|
|
17960
|
+
retiredFromFleet: true,
|
|
17961
|
+
retiredAt,
|
|
17962
|
+
lastError: "local agent card retired",
|
|
17963
|
+
lastFailedAt: retiredAt
|
|
17964
|
+
}
|
|
17965
|
+
};
|
|
17966
|
+
await brokerPostJson(broker.baseUrl, scoutBrokerPaths.v1.endpoints, nextEndpoint);
|
|
17967
|
+
broker.snapshot.endpoints[endpoint.id] = nextEndpoint;
|
|
17968
|
+
retired = true;
|
|
17969
|
+
}
|
|
17970
|
+
return retired;
|
|
17971
|
+
}
|
|
17309
17972
|
async function resolveConversationActorId(baseUrl, snapshot, nodeId, actorId, currentDirectory, displayName) {
|
|
17310
17973
|
const normalized = actorId.trim() || OPERATOR_ID;
|
|
17311
17974
|
if (snapshot.agents[normalized] || snapshot.actors[normalized]) {
|
|
@@ -18123,6 +18786,11 @@ async function attachScoutManagedLocalSession(input) {
|
|
|
18123
18786
|
async function sendScoutDirectMessage(input) {
|
|
18124
18787
|
const broker = await requireScoutBrokerContext();
|
|
18125
18788
|
const source = input.source?.trim() || "scout-mobile";
|
|
18789
|
+
const targetEndpoints = Object.values(broker.snapshot.endpoints ?? {}).filter((endpoint) => endpoint.agentId === input.agentId);
|
|
18790
|
+
const targetIsStale = isSupersededBrokerAgent(broker.snapshot, input.agentId) || targetEndpoints.length > 0 && targetEndpoints.every((endpoint) => metadataBoolean(endpoint.metadata, "retiredFromFleet") || metadataBoolean(endpoint.metadata, "staleLocalRegistration"));
|
|
18791
|
+
if (targetIsStale) {
|
|
18792
|
+
throw new Error(`${displayNameForBrokerActor(broker.snapshot, input.agentId)} is a stale local registration. Start the current project session from Workspaces before sending.`);
|
|
18793
|
+
}
|
|
18126
18794
|
const delivery = await brokerPostDeliver(broker.baseUrl, {
|
|
18127
18795
|
caller: {
|
|
18128
18796
|
actorId: OPERATOR_ID,
|
|
@@ -18185,6 +18853,41 @@ async function askScoutAgentById(input) {
|
|
|
18185
18853
|
workspace: input.workspace,
|
|
18186
18854
|
senderContext: input.senderContext,
|
|
18187
18855
|
labels: input.labels,
|
|
18856
|
+
replyToSessionId: input.replyToSessionId,
|
|
18857
|
+
currentDirectory: input.currentDirectory,
|
|
18858
|
+
source: input.source ?? "scout-mcp"
|
|
18859
|
+
});
|
|
18860
|
+
return {
|
|
18861
|
+
usedBroker: result.usedBroker,
|
|
18862
|
+
flight: result.flight,
|
|
18863
|
+
conversationId: result.conversationId,
|
|
18864
|
+
messageId: result.messageId,
|
|
18865
|
+
workItem: result.workItem,
|
|
18866
|
+
unresolvedTargetId: result.unresolvedTarget,
|
|
18867
|
+
targetDiagnostic: result.targetDiagnostic
|
|
18868
|
+
};
|
|
18869
|
+
}
|
|
18870
|
+
async function askScoutSessionById(input) {
|
|
18871
|
+
const targetSessionId = input.targetSessionId.trim();
|
|
18872
|
+
const result = await deliverScoutAsk({
|
|
18873
|
+
senderId: input.senderId,
|
|
18874
|
+
target: {
|
|
18875
|
+
kind: "session_id",
|
|
18876
|
+
sessionId: targetSessionId
|
|
18877
|
+
},
|
|
18878
|
+
targetLabel: `session:${targetSessionId}`,
|
|
18879
|
+
targetSessionId,
|
|
18880
|
+
body: input.body,
|
|
18881
|
+
workItem: input.workItem,
|
|
18882
|
+
channel: input.channel,
|
|
18883
|
+
shouldSpeak: input.shouldSpeak,
|
|
18884
|
+
createdAtMs: input.createdAtMs,
|
|
18885
|
+
executionHarness: input.executionHarness,
|
|
18886
|
+
executionSession: "existing",
|
|
18887
|
+
workspace: input.workspace,
|
|
18888
|
+
senderContext: input.senderContext,
|
|
18889
|
+
labels: input.labels,
|
|
18890
|
+
replyToSessionId: input.replyToSessionId,
|
|
18188
18891
|
currentDirectory: input.currentDirectory,
|
|
18189
18892
|
source: input.source ?? "scout-mcp"
|
|
18190
18893
|
});
|
|
@@ -18204,6 +18907,8 @@ function renderedScoutAskTarget(target) {
|
|
|
18204
18907
|
return target.agentId.trim();
|
|
18205
18908
|
case "agent_label":
|
|
18206
18909
|
return target.label.trim();
|
|
18910
|
+
case "session_id":
|
|
18911
|
+
return `session:${target.sessionId.trim()}`;
|
|
18207
18912
|
case "binding_ref":
|
|
18208
18913
|
return `ref:${target.ref.trim()}`;
|
|
18209
18914
|
case "project_path":
|
|
@@ -18217,8 +18922,11 @@ function renderedScoutAskTarget(target) {
|
|
|
18217
18922
|
function directAgentIdForAskTarget(target) {
|
|
18218
18923
|
return target.kind === "agent_id" ? target.agentId.trim() : undefined;
|
|
18219
18924
|
}
|
|
18925
|
+
function directSessionIdForAskTarget(target) {
|
|
18926
|
+
return target.kind === "session_id" ? target.sessionId.trim() : undefined;
|
|
18927
|
+
}
|
|
18220
18928
|
function defaultAskExecutionSession(target) {
|
|
18221
|
-
return target.kind === "binding_ref" ? "existing" : "new";
|
|
18929
|
+
return target.kind === "binding_ref" || target.kind === "session_id" ? "existing" : "new";
|
|
18222
18930
|
}
|
|
18223
18931
|
async function deliverScoutAsk(input) {
|
|
18224
18932
|
const broker = await loadScoutBrokerContext();
|
|
@@ -18235,6 +18943,7 @@ async function deliverScoutAsk(input) {
|
|
|
18235
18943
|
return { usedBroker: true, unresolvedTarget: renderedTarget };
|
|
18236
18944
|
}
|
|
18237
18945
|
const labels = normalizeWorkItemLabels(input.labels);
|
|
18946
|
+
const targetSessionId = directSessionIdForAskTarget(input.target) ?? input.targetSessionId?.trim();
|
|
18238
18947
|
const workRecordId = input.workItem ? buildScoutEntityId("work", createdAtMs) : undefined;
|
|
18239
18948
|
const deliveryWorkItem = input.workItem && workRecordId ? { id: workRecordId, ...input.workItem } : undefined;
|
|
18240
18949
|
const askMetadata = buildScoutAskMetadata({
|
|
@@ -18244,6 +18953,12 @@ async function deliverScoutAsk(input) {
|
|
|
18244
18953
|
workspace: input.workspace,
|
|
18245
18954
|
labels
|
|
18246
18955
|
});
|
|
18956
|
+
const replyToSessionId = input.replyToSessionId?.trim();
|
|
18957
|
+
const deliveryMetadata = targetSessionId || replyToSessionId ? {
|
|
18958
|
+
...askMetadata,
|
|
18959
|
+
...targetSessionId ? { targetSessionId } : {},
|
|
18960
|
+
...replyToSessionId ? { replyToSessionId } : {}
|
|
18961
|
+
} : askMetadata;
|
|
18247
18962
|
const delivery = await brokerPostDeliver(broker.baseUrl, {
|
|
18248
18963
|
caller: {
|
|
18249
18964
|
actorId: senderId,
|
|
@@ -18253,7 +18968,9 @@ async function deliverScoutAsk(input) {
|
|
|
18253
18968
|
},
|
|
18254
18969
|
target: input.target,
|
|
18255
18970
|
...targetAgentId ? { targetAgentId } : {},
|
|
18971
|
+
...targetSessionId ? { targetSessionId } : {},
|
|
18256
18972
|
targetLabel: renderedTarget,
|
|
18973
|
+
...replyToSessionId ? { replyToSessionId } : {},
|
|
18257
18974
|
body: input.body.trim(),
|
|
18258
18975
|
intent: "consult",
|
|
18259
18976
|
channel: input.channel,
|
|
@@ -18261,12 +18978,13 @@ async function deliverScoutAsk(input) {
|
|
|
18261
18978
|
...deliveryWorkItem ? { collaborationRecordId: workRecordId, workItem: deliveryWorkItem } : {},
|
|
18262
18979
|
execution: {
|
|
18263
18980
|
...input.executionHarness ? { harness: input.executionHarness } : {},
|
|
18981
|
+
...targetSessionId ? { targetSessionId } : {},
|
|
18264
18982
|
session: input.executionSession ?? defaultAskExecutionSession(input.target)
|
|
18265
18983
|
},
|
|
18266
18984
|
ensureAwake: true,
|
|
18267
18985
|
...labels ? { labels } : {},
|
|
18268
|
-
messageMetadata:
|
|
18269
|
-
invocationMetadata:
|
|
18986
|
+
messageMetadata: deliveryMetadata,
|
|
18987
|
+
invocationMetadata: deliveryMetadata
|
|
18270
18988
|
});
|
|
18271
18989
|
if (delivery.kind !== "delivery") {
|
|
18272
18990
|
return {
|
|
@@ -18311,6 +19029,8 @@ async function askScoutQuestion(input) {
|
|
|
18311
19029
|
workspace: input.workspace,
|
|
18312
19030
|
senderContext: input.senderContext,
|
|
18313
19031
|
labels: input.labels,
|
|
19032
|
+
targetSessionId: input.targetSessionId,
|
|
19033
|
+
replyToSessionId: input.replyToSessionId,
|
|
18314
19034
|
currentDirectory: input.currentDirectory,
|
|
18315
19035
|
source: input.source ?? "scout-cli"
|
|
18316
19036
|
});
|
|
@@ -18329,6 +19049,16 @@ async function loadScoutInvocationSnapshot(baseUrl, invocationId) {
|
|
|
18329
19049
|
}
|
|
18330
19050
|
return snapshot;
|
|
18331
19051
|
}
|
|
19052
|
+
async function loadScoutInvocationLifecycle(baseUrl, invocationId) {
|
|
19053
|
+
try {
|
|
19054
|
+
return await brokerReadJson(baseUrl, scoutBrokerInvocationLifecyclePath(invocationId));
|
|
19055
|
+
} catch (error) {
|
|
19056
|
+
if (error instanceof Error && error.message.includes(`${scoutBrokerInvocationLifecyclePath(invocationId)} returned 404`)) {
|
|
19057
|
+
return null;
|
|
19058
|
+
}
|
|
19059
|
+
throw error;
|
|
19060
|
+
}
|
|
19061
|
+
}
|
|
18332
19062
|
async function resolveScoutWaitReference(baseUrl, input) {
|
|
18333
19063
|
const original = input.trim();
|
|
18334
19064
|
const normalized = normalizeScoutWaitRef(original);
|
|
@@ -18662,6 +19392,18 @@ async function readScoutBrokerFeed(options) {
|
|
|
18662
19392
|
return null;
|
|
18663
19393
|
}
|
|
18664
19394
|
}
|
|
19395
|
+
async function markScoutConversationRead(options = {}) {
|
|
19396
|
+
const broker = await requireScoutBrokerContext(options.baseUrl);
|
|
19397
|
+
const conversationId = options.conversationId ?? scoutConversationIdForChannel(options.channel);
|
|
19398
|
+
return brokerPostJson(broker.baseUrl, `/v1/conversations/${encodeURIComponent(conversationId)}/read-cursors`, {
|
|
19399
|
+
actorId: options.actorId,
|
|
19400
|
+
readerNodeId: options.readerNodeId ?? broker.node.id,
|
|
19401
|
+
lastReadMessageId: options.lastReadMessageId,
|
|
19402
|
+
lastReadSeq: options.lastReadSeq,
|
|
19403
|
+
lastReadAt: options.lastReadAt,
|
|
19404
|
+
metadata: options.metadata
|
|
19405
|
+
});
|
|
19406
|
+
}
|
|
18665
19407
|
async function loadScoutActivityItems(options = {}) {
|
|
18666
19408
|
const search = new URLSearchParams;
|
|
18667
19409
|
if (options.agentId)
|
|
@@ -18793,9 +19535,20 @@ async function loadConfiguredAgentIds() {
|
|
|
18793
19535
|
return new Set;
|
|
18794
19536
|
}
|
|
18795
19537
|
}
|
|
19538
|
+
async function loadDiscoveredAgentMap(currentDirectory) {
|
|
19539
|
+
try {
|
|
19540
|
+
const setup = await loadResolvedRelayAgents({ currentDirectory });
|
|
19541
|
+
return new Map(setup.discoveredAgents.map((agent) => [agent.agentId, agent]));
|
|
19542
|
+
} catch {
|
|
19543
|
+
return new Map;
|
|
19544
|
+
}
|
|
19545
|
+
}
|
|
18796
19546
|
async function listScoutAgents(options = {}) {
|
|
18797
19547
|
const broker = await requireScoutBrokerContext();
|
|
18798
|
-
const configuredAgentIds = await
|
|
19548
|
+
const [configuredAgentIds, discoveredAgents] = await Promise.all([
|
|
19549
|
+
loadConfiguredAgentIds(),
|
|
19550
|
+
loadDiscoveredAgentMap(options.currentDirectory ?? process.cwd())
|
|
19551
|
+
]);
|
|
18799
19552
|
const endpointsByAgent = new Map;
|
|
18800
19553
|
const messageStats = new Map;
|
|
18801
19554
|
for (const endpoint of Object.values(broker.snapshot.endpoints ?? {})) {
|
|
@@ -18832,12 +19585,13 @@ async function listScoutAgents(options = {}) {
|
|
|
18832
19585
|
...Object.keys(broker.snapshot.agents ?? {}),
|
|
18833
19586
|
...Array.from(endpointsByAgent.keys()),
|
|
18834
19587
|
...Array.from(messageStats.keys()),
|
|
18835
|
-
...Array.from(configuredAgentIds.values())
|
|
19588
|
+
...Array.from(configuredAgentIds.values()),
|
|
19589
|
+
...Array.from(discoveredAgents.keys())
|
|
18836
19590
|
])
|
|
18837
19591
|
].filter((agentId) => agentId && agentId !== OPERATOR_ID).filter((agentId) => !isBuiltInBrokerAgent(broker.snapshot, agentId)).filter((agentId) => !isSupersededBrokerAgent(broker.snapshot, agentId)).map((agentId) => {
|
|
18838
19592
|
const endpoints = endpointsByAgent.get(agentId) ?? [];
|
|
18839
19593
|
const brokerMessages = messageStats.get(agentId);
|
|
18840
|
-
const registrationKind = configuredAgentIds.has(agentId) ? "configured" : "broker";
|
|
19594
|
+
const registrationKind = discoveredAgents.get(agentId)?.registrationKind ?? (configuredAgentIds.has(agentId) ? "configured" : "broker");
|
|
18841
19595
|
const state = whoEntryState(endpoints, registrationKind);
|
|
18842
19596
|
const lastSeen = maxDefined([
|
|
18843
19597
|
brokerMessages?.lastSeen,
|
|
@@ -19099,6 +19853,8 @@ function renderedAskTarget(target) {
|
|
|
19099
19853
|
return target.agentId;
|
|
19100
19854
|
case "agent_label":
|
|
19101
19855
|
return target.label;
|
|
19856
|
+
case "session_id":
|
|
19857
|
+
return `session:${target.sessionId}`;
|
|
19102
19858
|
case "binding_ref":
|
|
19103
19859
|
return `ref:${target.ref}`;
|
|
19104
19860
|
case "project_path":
|
|
@@ -19120,6 +19876,9 @@ function askTargetFor(to) {
|
|
|
19120
19876
|
if (parsed.kind === "binding_ref") {
|
|
19121
19877
|
return { kind: "binding_ref", ref: parsed.ref };
|
|
19122
19878
|
}
|
|
19879
|
+
if (parsed.kind === "session_id") {
|
|
19880
|
+
return { kind: "session_id", sessionId: parsed.sessionId };
|
|
19881
|
+
}
|
|
19123
19882
|
if (parsed.kind === "agent_label") {
|
|
19124
19883
|
return { kind: "agent_label", label: parsed.label };
|
|
19125
19884
|
}
|
|
@@ -19200,6 +19959,7 @@ var scoutAskHandler = async (command) => {
|
|
|
19200
19959
|
body: command.body,
|
|
19201
19960
|
workItem: command.workItem,
|
|
19202
19961
|
labels: command.labels,
|
|
19962
|
+
replyToSessionId: command.replyToSessionId,
|
|
19203
19963
|
channel: command.channel,
|
|
19204
19964
|
shouldSpeak: command.shouldSpeak,
|
|
19205
19965
|
executionHarness: command.harness,
|
|
@@ -19239,11 +19999,14 @@ function renderAskCommandHelp() {
|
|
|
19239
19999
|
" one target + no channel -> DM",
|
|
19240
20000
|
" --channel <name> -> named group thread",
|
|
19241
20001
|
" short @name -> must resolve to exactly one routable agent",
|
|
20002
|
+
" --project <path> -> ask by repo/workspace path; Scout resolves the concrete agent/session",
|
|
20003
|
+
" '>> project:<path> ...' -> composer route form for the same project-path ask",
|
|
19242
20004
|
"",
|
|
19243
20005
|
'Use ask when the meaning is "do this and get back to me."',
|
|
19244
20006
|
"The command creates durable broker work; the target should acknowledge quickly in the same DM or channel.",
|
|
19245
20007
|
`Default inline mode returns once the target has acknowledged, completed immediately, or stays unacknowledged for ${DEFAULT_ASK_ACK_TIMEOUT_SECONDS}s.`,
|
|
19246
20008
|
"Use the flight id, conversation, notify mode, or an explicit wait to follow the final completion.",
|
|
20009
|
+
"Use --project when you know the project path but do not want to look up or pin an agent id first.",
|
|
19247
20010
|
"",
|
|
19248
20011
|
"Input:",
|
|
19249
20012
|
" inline message -> primary prompt body",
|
|
@@ -19254,6 +20017,8 @@ function renderAskCommandHelp() {
|
|
|
19254
20017
|
' scout ask --to hudson "review the parser"',
|
|
19255
20018
|
' scout ask --ref 7f3a9c21 "continue from that result"',
|
|
19256
20019
|
' scout ask --project ../talkie "how did you handle auth?"',
|
|
20020
|
+
' scout ask --project ../talkie --harness codex "review this from a fresh Codex session"',
|
|
20021
|
+
" scout ask '>> project:../talkie compare auth against this branch'",
|
|
19257
20022
|
" scout ask --to hudson --prompt-file ./handoff.md",
|
|
19258
20023
|
' scout ask --as premotion.master.mini --to hudson "build the editor"',
|
|
19259
20024
|
' scout ask --to hudson --reply-mode notify "take the next pass and report back"',
|
|
@@ -19862,6 +20627,7 @@ function buildScoutAgentCard(binding, options = {}) {
|
|
|
19862
20627
|
const supportedInterfaces = metadataRecordArray(binding.agent.metadata, "supportedInterfaces");
|
|
19863
20628
|
const securitySchemes = metadataRecord2(binding.agent.metadata, "securitySchemes");
|
|
19864
20629
|
const securityRequirements = metadataStringMatrix(binding.agent.metadata, "securityRequirements");
|
|
20630
|
+
const lifecycle2 = options.lifecycle ?? metadataRecord2(binding.agent.metadata, "cardLifecycle");
|
|
19865
20631
|
return {
|
|
19866
20632
|
id: binding.agent.id,
|
|
19867
20633
|
agentId: binding.agent.id,
|
|
@@ -19891,6 +20657,7 @@ function buildScoutAgentCard(binding, options = {}) {
|
|
|
19891
20657
|
...options.createdById?.trim() ? { createdById: options.createdById.trim() } : {},
|
|
19892
20658
|
brokerRegistered: options.brokerRegistered ?? false,
|
|
19893
20659
|
...options.inboxConversationId?.trim() ? { inboxConversationId: options.inboxConversationId.trim() } : {},
|
|
20660
|
+
...lifecycle2 ? { lifecycle: lifecycle2 } : {},
|
|
19894
20661
|
returnAddress: buildScoutReturnAddress({
|
|
19895
20662
|
actorId: binding.agent.id,
|
|
19896
20663
|
handle,
|
|
@@ -19908,7 +20675,8 @@ function buildScoutAgentCard(binding, options = {}) {
|
|
|
19908
20675
|
actorId: binding.actor.id,
|
|
19909
20676
|
endpointId: binding.endpoint.id,
|
|
19910
20677
|
wakePolicy: binding.agent.wakePolicy,
|
|
19911
|
-
...model ? { model } : {}
|
|
20678
|
+
...model ? { model } : {},
|
|
20679
|
+
...lifecycle2 ? { cardLifecycle: lifecycle2 } : {}
|
|
19912
20680
|
}
|
|
19913
20681
|
};
|
|
19914
20682
|
}
|
|
@@ -19917,13 +20685,24 @@ var init_scout_agent_cards = __esm(() => {
|
|
|
19917
20685
|
});
|
|
19918
20686
|
|
|
19919
20687
|
// ../runtime/src/control-plane-agents.ts
|
|
20688
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
20689
|
+
import { basename as basename11 } from "path";
|
|
20690
|
+
function oneTimeAgentName(input) {
|
|
20691
|
+
const base = normalizeAgentSelectorSegment(input.agentName || basename11(input.projectPath)) || "agent";
|
|
20692
|
+
return `${base}-card-${randomUUID2().slice(0, 8)}`;
|
|
20693
|
+
}
|
|
19920
20694
|
function createScoutAgentService(deps) {
|
|
19921
20695
|
const localAgents = {
|
|
19922
20696
|
listLocalAgents: deps.localAgents?.listLocalAgents ?? listLocalAgents,
|
|
20697
|
+
retireLocalAgent: deps.localAgents?.retireLocalAgent ?? retireLocalAgent,
|
|
19923
20698
|
restartAllLocalAgents: deps.localAgents?.restartAllLocalAgents ?? restartAllLocalAgents,
|
|
20699
|
+
restartLocalAgent: deps.localAgents?.restartLocalAgent ?? restartLocalAgent,
|
|
19924
20700
|
startLocalAgent: deps.localAgents?.startLocalAgent ?? startLocalAgent,
|
|
19925
20701
|
stopAllLocalAgents: deps.localAgents?.stopAllLocalAgents ?? stopAllLocalAgents,
|
|
19926
20702
|
stopLocalAgent: deps.localAgents?.stopLocalAgent ?? stopLocalAgent,
|
|
20703
|
+
updateLocalAgentCard: deps.localAgents?.updateLocalAgentCard ?? updateLocalAgentCard,
|
|
20704
|
+
updateLocalAgentCardLifecycle: deps.localAgents?.updateLocalAgentCardLifecycle ?? updateLocalAgentCardLifecycle,
|
|
20705
|
+
pruneOneTimeLocalAgentCards: deps.localAgents?.pruneOneTimeLocalAgentCards ?? pruneOneTimeLocalAgentCards,
|
|
19927
20706
|
inferLocalAgentBinding: deps.localAgents?.inferLocalAgentBinding ?? inferLocalAgentBinding
|
|
19928
20707
|
};
|
|
19929
20708
|
return {
|
|
@@ -19940,22 +20719,62 @@ function createScoutAgentService(deps) {
|
|
|
19940
20719
|
async downScoutAgent(agentId) {
|
|
19941
20720
|
return localAgents.stopLocalAgent(agentId);
|
|
19942
20721
|
},
|
|
20722
|
+
async retireScoutAgentCard(agentId) {
|
|
20723
|
+
const broker = await deps.loadScoutBrokerContext().catch(() => null);
|
|
20724
|
+
const retired = await localAgents.retireLocalAgent(agentId);
|
|
20725
|
+
if (retired) {
|
|
20726
|
+
await deps.retireScoutLocalAgentBinding?.({ agentId, broker }).catch(() => false);
|
|
20727
|
+
}
|
|
20728
|
+
return retired;
|
|
20729
|
+
},
|
|
20730
|
+
async updateScoutAgentCard(agentId, input) {
|
|
20731
|
+
const config = await localAgents.updateLocalAgentCard(agentId, input);
|
|
20732
|
+
if (!config) {
|
|
20733
|
+
return null;
|
|
20734
|
+
}
|
|
20735
|
+
if (input.restart === true) {
|
|
20736
|
+
await localAgents.restartLocalAgent(agentId);
|
|
20737
|
+
}
|
|
20738
|
+
await deps.registerScoutLocalAgentBinding({ agentId }).catch(() => {});
|
|
20739
|
+
return config;
|
|
20740
|
+
},
|
|
19943
20741
|
async downAllScoutAgents(input = {}) {
|
|
19944
20742
|
return localAgents.stopAllLocalAgents(input);
|
|
19945
20743
|
},
|
|
19946
20744
|
async restartScoutAgents(input = {}) {
|
|
19947
20745
|
return localAgents.restartAllLocalAgents(input);
|
|
19948
20746
|
},
|
|
20747
|
+
async cleanupScoutAgentCards(input = {}) {
|
|
20748
|
+
const broker = await deps.loadScoutBrokerContext().catch(() => null);
|
|
20749
|
+
const result = await localAgents.pruneOneTimeLocalAgentCards(input);
|
|
20750
|
+
await Promise.all(result.retired.map((status) => deps.retireScoutLocalAgentBinding?.({ agentId: status.agentId, broker }).catch(() => false)));
|
|
20751
|
+
return result;
|
|
20752
|
+
},
|
|
19949
20753
|
async createScoutAgentCard(input) {
|
|
20754
|
+
const createdAt = Date.now();
|
|
20755
|
+
const oneTimeUse = input.oneTimeUse === true;
|
|
20756
|
+
const createdById = input.createdById?.trim() || undefined;
|
|
20757
|
+
const agentName = oneTimeUse ? oneTimeAgentName({
|
|
20758
|
+
agentName: input.agentName,
|
|
20759
|
+
projectPath: input.projectPath
|
|
20760
|
+
}) : input.agentName;
|
|
20761
|
+
const lifecycle2 = oneTimeUse ? {
|
|
20762
|
+
kind: "one_time",
|
|
20763
|
+
createdAt,
|
|
20764
|
+
...createdById ? { createdById } : {},
|
|
20765
|
+
expiresAt: createdAt + Math.max(1, input.ttlMs ?? DEFAULT_ONE_TIME_SCOUT_AGENT_CARD_TTL_MS),
|
|
20766
|
+
maxUses: 1
|
|
20767
|
+
} : undefined;
|
|
19950
20768
|
const status = await localAgents.startLocalAgent({
|
|
19951
20769
|
projectPath: input.projectPath,
|
|
19952
|
-
agentName
|
|
20770
|
+
agentName,
|
|
19953
20771
|
displayName: input.displayName,
|
|
19954
20772
|
harness: input.harness,
|
|
19955
20773
|
model: input.model,
|
|
19956
20774
|
reasoningEffort: input.reasoningEffort,
|
|
19957
20775
|
permissionProfile: input.permissionProfile,
|
|
19958
20776
|
currentDirectory: input.currentDirectory,
|
|
20777
|
+
...lifecycle2 ? { card: lifecycle2 } : {},
|
|
19959
20778
|
ensureOnline: false
|
|
19960
20779
|
});
|
|
19961
20780
|
const currentDirectory = input.currentDirectory ?? input.projectPath;
|
|
@@ -19969,48 +20788,70 @@ function createScoutAgentService(deps) {
|
|
|
19969
20788
|
throw new Error(`Agent ${status.agentId} did not expose an addressable binding.`);
|
|
19970
20789
|
}
|
|
19971
20790
|
let inboxConversationId;
|
|
19972
|
-
let
|
|
19973
|
-
if (broker &&
|
|
20791
|
+
let resolvedCreatedById = createdById;
|
|
20792
|
+
if (broker && resolvedCreatedById && resolvedCreatedById !== binding.agent.id) {
|
|
19974
20793
|
const session = await deps.openScoutPeerSession({
|
|
19975
|
-
sourceId:
|
|
20794
|
+
sourceId: resolvedCreatedById,
|
|
19976
20795
|
targetId: binding.agent.id,
|
|
19977
20796
|
currentDirectory
|
|
19978
20797
|
});
|
|
19979
20798
|
inboxConversationId = session.conversation.id;
|
|
19980
|
-
|
|
20799
|
+
resolvedCreatedById = session.sourceId;
|
|
20800
|
+
}
|
|
20801
|
+
const finalLifecycle = lifecycle2 ? {
|
|
20802
|
+
...lifecycle2,
|
|
20803
|
+
...resolvedCreatedById ? { createdById: resolvedCreatedById } : {},
|
|
20804
|
+
...inboxConversationId ? { inboxConversationId } : {}
|
|
20805
|
+
} : undefined;
|
|
20806
|
+
if (finalLifecycle) {
|
|
20807
|
+
await localAgents.updateLocalAgentCardLifecycle(status.agentId, finalLifecycle).catch(() => null);
|
|
20808
|
+
const cleaned = await localAgents.pruneOneTimeLocalAgentCards({
|
|
20809
|
+
createdById: finalLifecycle.createdById,
|
|
20810
|
+
projectRoot: binding.endpoint.projectRoot ?? input.projectPath,
|
|
20811
|
+
excludeAgentIds: [status.agentId]
|
|
20812
|
+
}).catch(() => null);
|
|
20813
|
+
if (cleaned?.retired.length) {
|
|
20814
|
+
await Promise.all(cleaned.retired.map((retired) => deps.retireScoutLocalAgentBinding?.({ agentId: retired.agentId, broker }).catch(() => false)));
|
|
20815
|
+
}
|
|
19981
20816
|
}
|
|
19982
20817
|
return buildScoutAgentCard(binding, {
|
|
19983
20818
|
currentDirectory,
|
|
19984
|
-
createdById,
|
|
20819
|
+
createdById: resolvedCreatedById,
|
|
19985
20820
|
brokerRegistered: syncResult?.brokerRegistered ?? false,
|
|
19986
|
-
inboxConversationId
|
|
20821
|
+
inboxConversationId,
|
|
20822
|
+
lifecycle: finalLifecycle
|
|
19987
20823
|
});
|
|
19988
20824
|
}
|
|
19989
20825
|
};
|
|
19990
20826
|
}
|
|
20827
|
+
var DEFAULT_ONE_TIME_SCOUT_AGENT_CARD_TTL_MS;
|
|
19991
20828
|
var init_control_plane_agents = __esm(() => {
|
|
20829
|
+
init_src();
|
|
19992
20830
|
init_local_agents();
|
|
19993
20831
|
init_scout_agent_cards();
|
|
20832
|
+
DEFAULT_ONE_TIME_SCOUT_AGENT_CARD_TTL_MS = 24 * 60 * 60 * 1000;
|
|
19994
20833
|
});
|
|
19995
20834
|
|
|
19996
20835
|
// ../../apps/desktop/src/core/agents/service.ts
|
|
19997
|
-
var scoutAgentService, createScoutAgentCard, downAllScoutAgents, downScoutAgent, loadScoutAgentStatuses, restartScoutAgents, upScoutAgent;
|
|
20836
|
+
var scoutAgentService, cleanupScoutAgentCards, createScoutAgentCard, downAllScoutAgents, downScoutAgent, loadScoutAgentStatuses, retireScoutAgentCard, restartScoutAgents, updateScoutAgentCard, upScoutAgent;
|
|
19998
20837
|
var init_service2 = __esm(() => {
|
|
19999
20838
|
init_control_plane_agents();
|
|
20000
20839
|
init_service();
|
|
20001
20840
|
scoutAgentService = createScoutAgentService({
|
|
20002
20841
|
loadScoutBrokerContext,
|
|
20003
20842
|
openScoutPeerSession,
|
|
20004
|
-
registerScoutLocalAgentBinding
|
|
20005
|
-
|
|
20006
|
-
|
|
20007
|
-
|
|
20008
|
-
|
|
20009
|
-
|
|
20010
|
-
|
|
20011
|
-
|
|
20012
|
-
|
|
20013
|
-
|
|
20843
|
+
registerScoutLocalAgentBinding,
|
|
20844
|
+
retireScoutLocalAgentBinding
|
|
20845
|
+
});
|
|
20846
|
+
cleanupScoutAgentCards = scoutAgentService.cleanupScoutAgentCards;
|
|
20847
|
+
createScoutAgentCard = scoutAgentService.createScoutAgentCard;
|
|
20848
|
+
downAllScoutAgents = scoutAgentService.downAllScoutAgents;
|
|
20849
|
+
downScoutAgent = scoutAgentService.downScoutAgent;
|
|
20850
|
+
loadScoutAgentStatuses = scoutAgentService.loadScoutAgentStatuses;
|
|
20851
|
+
retireScoutAgentCard = scoutAgentService.retireScoutAgentCard;
|
|
20852
|
+
restartScoutAgents = scoutAgentService.restartScoutAgents;
|
|
20853
|
+
updateScoutAgentCard = scoutAgentService.updateScoutAgentCard;
|
|
20854
|
+
upScoutAgent = scoutAgentService.upScoutAgent;
|
|
20014
20855
|
});
|
|
20015
20856
|
|
|
20016
20857
|
// ../../apps/desktop/src/ui/terminal/cards.ts
|
|
@@ -20078,16 +20919,129 @@ __export(exports_card, {
|
|
|
20078
20919
|
import { createInterface } from "readline";
|
|
20079
20920
|
function renderCardCommandHelp() {
|
|
20080
20921
|
return [
|
|
20081
|
-
"Usage:
|
|
20922
|
+
"Usage:",
|
|
20923
|
+
" scout card create [path] [--name <alias>] [--display-name <name>] [--harness <claude|codex|pi>] [--model <model>] [--reasoning-effort <effort>] [--permission-profile <profile>] [--as <requester>] [--one-time] [--no-input] [--path <path>]",
|
|
20924
|
+
` scout card update <agent> [--harness <claude|codex|pi>] [--model <model>|--clear-model] [--reasoning-effort <effort>|--clear-reasoning-effort] [--permission-profile <${formatScoutPermissionProfiles()}>|--clear-permission-profile] [--restart]`,
|
|
20925
|
+
" scout card cleanup [--all]",
|
|
20926
|
+
" scout card retire <agent>",
|
|
20082
20927
|
"",
|
|
20083
|
-
"Create a dedicated Scout agent card with a reply-ready return address.",
|
|
20928
|
+
"Create, update, or retire a dedicated Scout agent card with a reply-ready return address.",
|
|
20084
20929
|
"",
|
|
20085
20930
|
"Use this when another agent should get back to you on a fresh project-scoped inbox,",
|
|
20086
20931
|
"or when a worktree needs its own obvious handle instead of reusing a shared project agent.",
|
|
20087
20932
|
"",
|
|
20088
20933
|
"Examples:",
|
|
20089
20934
|
" scout card create",
|
|
20090
|
-
" scout card create ~/dev/openscout-worktrees/shell-fix --name shellfix --harness claude --model claude-sonnet-4-6"
|
|
20935
|
+
" scout card create ~/dev/openscout-worktrees/shell-fix --name shellfix --harness claude --model claude-sonnet-4-6",
|
|
20936
|
+
" scout card create --one-time --name review",
|
|
20937
|
+
" scout card cleanup",
|
|
20938
|
+
" scout card update talkie-drift-investigator --harness claude --model claude-opus-4-7",
|
|
20939
|
+
" scout card retire talkie-drift-investigator"
|
|
20940
|
+
].join(`
|
|
20941
|
+
`);
|
|
20942
|
+
}
|
|
20943
|
+
function readRequiredFlagValue(args, index, flag) {
|
|
20944
|
+
const current = args[index] ?? "";
|
|
20945
|
+
if (current.startsWith(`${flag}=`)) {
|
|
20946
|
+
return { value: current.slice(flag.length + 1), index };
|
|
20947
|
+
}
|
|
20948
|
+
const value = args[index + 1];
|
|
20949
|
+
if (!value) {
|
|
20950
|
+
throw new ScoutCliError(`missing value for ${flag}`);
|
|
20951
|
+
}
|
|
20952
|
+
return { value, index: index + 1 };
|
|
20953
|
+
}
|
|
20954
|
+
function parseCardUpdateOptions(args) {
|
|
20955
|
+
const target = args[0]?.trim();
|
|
20956
|
+
if (!target) {
|
|
20957
|
+
throw new ScoutCliError(renderCardCommandHelp());
|
|
20958
|
+
}
|
|
20959
|
+
const options = { restart: false };
|
|
20960
|
+
for (let index = 1;index < args.length; index += 1) {
|
|
20961
|
+
const current = args[index] ?? "";
|
|
20962
|
+
if (current === "--harness" || current.startsWith("--harness=")) {
|
|
20963
|
+
const parsed = readRequiredFlagValue(args, index, "--harness");
|
|
20964
|
+
options.harness = parsed.value;
|
|
20965
|
+
index = parsed.index;
|
|
20966
|
+
continue;
|
|
20967
|
+
}
|
|
20968
|
+
if (current === "--model" || current.startsWith("--model=")) {
|
|
20969
|
+
const parsed = readRequiredFlagValue(args, index, "--model");
|
|
20970
|
+
options.model = parsed.value;
|
|
20971
|
+
index = parsed.index;
|
|
20972
|
+
continue;
|
|
20973
|
+
}
|
|
20974
|
+
if (current === "--clear-model") {
|
|
20975
|
+
options.model = null;
|
|
20976
|
+
continue;
|
|
20977
|
+
}
|
|
20978
|
+
if (current === "--reasoning-effort" || current === "--effort" || current.startsWith("--reasoning-effort=") || current.startsWith("--effort=")) {
|
|
20979
|
+
const flag = current.startsWith("--effort") ? "--effort" : "--reasoning-effort";
|
|
20980
|
+
const parsed = readRequiredFlagValue(args, index, flag);
|
|
20981
|
+
options.reasoningEffort = parsed.value;
|
|
20982
|
+
index = parsed.index;
|
|
20983
|
+
continue;
|
|
20984
|
+
}
|
|
20985
|
+
if (current === "--clear-reasoning-effort") {
|
|
20986
|
+
options.reasoningEffort = null;
|
|
20987
|
+
continue;
|
|
20988
|
+
}
|
|
20989
|
+
if (current === "--permission-profile" || current.startsWith("--permission-profile=")) {
|
|
20990
|
+
const parsed = readRequiredFlagValue(args, index, "--permission-profile");
|
|
20991
|
+
options.permissionProfile = parsed.value;
|
|
20992
|
+
index = parsed.index;
|
|
20993
|
+
continue;
|
|
20994
|
+
}
|
|
20995
|
+
if (current === "--clear-permission-profile") {
|
|
20996
|
+
options.permissionProfile = null;
|
|
20997
|
+
continue;
|
|
20998
|
+
}
|
|
20999
|
+
if (current === "--restart") {
|
|
21000
|
+
options.restart = true;
|
|
21001
|
+
continue;
|
|
21002
|
+
}
|
|
21003
|
+
if (current.startsWith("--")) {
|
|
21004
|
+
throw new ScoutCliError(`unexpected argument for card update: ${current}`);
|
|
21005
|
+
}
|
|
21006
|
+
throw new ScoutCliError(`unexpected arguments for card update: ${args.join(" ")}`);
|
|
21007
|
+
}
|
|
21008
|
+
return { target, options };
|
|
21009
|
+
}
|
|
21010
|
+
async function resolveCardAgentId(target) {
|
|
21011
|
+
const resolved = await resolveLocalAgentByName(target) ?? await resolveLocalAgentByName(target, { matchProjectName: true });
|
|
21012
|
+
if (!resolved) {
|
|
21013
|
+
throw new ScoutCliError(`unknown Scout card "${target}"`);
|
|
21014
|
+
}
|
|
21015
|
+
return resolved.agentId;
|
|
21016
|
+
}
|
|
21017
|
+
function renderCardUpdateResult(value) {
|
|
21018
|
+
return [
|
|
21019
|
+
`Updated ${value.agentId}`,
|
|
21020
|
+
`Harness: ${value.config.runtime.harness}`,
|
|
21021
|
+
`Transport: ${value.config.runtime.transport}`,
|
|
21022
|
+
`Session: ${value.config.runtime.sessionId}`,
|
|
21023
|
+
`Model: ${value.config.model ?? "default"}`,
|
|
21024
|
+
`Permission: ${value.config.permissionProfile ?? "default"}`,
|
|
21025
|
+
`Restarted: ${value.restarted ? "yes" : "no"}`
|
|
21026
|
+
].join(`
|
|
21027
|
+
`);
|
|
21028
|
+
}
|
|
21029
|
+
function renderCardRetireResult(value) {
|
|
21030
|
+
if (!value) {
|
|
21031
|
+
return "Agent not found.";
|
|
21032
|
+
}
|
|
21033
|
+
return `Retired ${value.agentId}`;
|
|
21034
|
+
}
|
|
21035
|
+
function renderCardCleanupResult(value) {
|
|
21036
|
+
const count = value.retired.length;
|
|
21037
|
+
if (count === 0) {
|
|
21038
|
+
return `No one-time cards retired. Inspected ${value.inspected}.`;
|
|
21039
|
+
}
|
|
21040
|
+
const agents = value.retired.map((agent) => `- ${agent.agentId}`).join(`
|
|
21041
|
+
`);
|
|
21042
|
+
return [
|
|
21043
|
+
`Retired ${count} one-time card${count === 1 ? "" : "s"}.`,
|
|
21044
|
+
agents
|
|
20091
21045
|
].join(`
|
|
20092
21046
|
`);
|
|
20093
21047
|
}
|
|
@@ -20106,6 +21060,60 @@ async function runCardCommand(context, args) {
|
|
|
20106
21060
|
context.output.writeText(renderCardCommandHelp());
|
|
20107
21061
|
return;
|
|
20108
21062
|
}
|
|
21063
|
+
if (subcommand === "update") {
|
|
21064
|
+
if (args.slice(1).some((arg) => HELP_FLAGS4.has(arg))) {
|
|
21065
|
+
context.output.writeText(renderCardCommandHelp());
|
|
21066
|
+
return;
|
|
21067
|
+
}
|
|
21068
|
+
const { target, options: options2 } = parseCardUpdateOptions(args.slice(1));
|
|
21069
|
+
const agentId = await resolveCardAgentId(target);
|
|
21070
|
+
const config = await updateScoutAgentCard(agentId, {
|
|
21071
|
+
harness: parseScoutLocalHarness(options2.harness),
|
|
21072
|
+
model: options2.model,
|
|
21073
|
+
reasoningEffort: options2.reasoningEffort,
|
|
21074
|
+
permissionProfile: options2.permissionProfile,
|
|
21075
|
+
restart: options2.restart
|
|
21076
|
+
});
|
|
21077
|
+
if (!config) {
|
|
21078
|
+
throw new ScoutCliError(`unknown Scout card "${target}"`);
|
|
21079
|
+
}
|
|
21080
|
+
context.output.writeValue({ agentId, config, restarted: options2.restart }, renderCardUpdateResult);
|
|
21081
|
+
return;
|
|
21082
|
+
}
|
|
21083
|
+
if (subcommand === "retire" || subcommand === "delete" || subcommand === "remove") {
|
|
21084
|
+
if (args.slice(1).some((arg) => HELP_FLAGS4.has(arg))) {
|
|
21085
|
+
context.output.writeText(renderCardCommandHelp());
|
|
21086
|
+
return;
|
|
21087
|
+
}
|
|
21088
|
+
const target = args[1]?.trim();
|
|
21089
|
+
if (!target || args.length > 2) {
|
|
21090
|
+
throw new ScoutCliError(renderCardCommandHelp());
|
|
21091
|
+
}
|
|
21092
|
+
const agentId = await resolveCardAgentId(target);
|
|
21093
|
+
const retired = await retireScoutAgentCard(agentId);
|
|
21094
|
+
context.output.writeValue(retired, renderCardRetireResult);
|
|
21095
|
+
return;
|
|
21096
|
+
}
|
|
21097
|
+
if (subcommand === "cleanup" || subcommand === "prune") {
|
|
21098
|
+
if (args.slice(1).some((arg) => HELP_FLAGS4.has(arg))) {
|
|
21099
|
+
context.output.writeText(renderCardCommandHelp());
|
|
21100
|
+
return;
|
|
21101
|
+
}
|
|
21102
|
+
let all = false;
|
|
21103
|
+
for (const arg of args.slice(1)) {
|
|
21104
|
+
if (arg === "--all") {
|
|
21105
|
+
all = true;
|
|
21106
|
+
continue;
|
|
21107
|
+
}
|
|
21108
|
+
throw new ScoutCliError(`unexpected argument for card cleanup: ${arg}`);
|
|
21109
|
+
}
|
|
21110
|
+
const cleaned = await cleanupScoutAgentCards({
|
|
21111
|
+
currentDirectory: defaultScoutContextDirectory(context),
|
|
21112
|
+
maxCount: all ? 0 : undefined
|
|
21113
|
+
});
|
|
21114
|
+
context.output.writeValue(cleaned, renderCardCleanupResult);
|
|
21115
|
+
return;
|
|
21116
|
+
}
|
|
20109
21117
|
if (subcommand !== "create") {
|
|
20110
21118
|
throw new ScoutCliError(renderCardCommandHelp());
|
|
20111
21119
|
}
|
|
@@ -20155,12 +21163,14 @@ async function runCardCommand(context, args) {
|
|
|
20155
21163
|
reasoningEffort: options.reasoningEffort,
|
|
20156
21164
|
permissionProfile: options.permissionProfile,
|
|
20157
21165
|
currentDirectory: options.currentDirectory,
|
|
20158
|
-
createdById: resolveScoutAgentName(options.requesterId)
|
|
21166
|
+
createdById: resolveScoutAgentName(options.requesterId),
|
|
21167
|
+
oneTimeUse: options.oneTimeUse
|
|
20159
21168
|
});
|
|
20160
21169
|
context.output.writeValue(card, renderScoutAgentCard);
|
|
20161
21170
|
}
|
|
20162
21171
|
var HELP_FLAGS4;
|
|
20163
21172
|
var init_card = __esm(() => {
|
|
21173
|
+
init_src();
|
|
20164
21174
|
init_local_agents();
|
|
20165
21175
|
init_context();
|
|
20166
21176
|
init_errors();
|
|
@@ -48656,17 +49666,29 @@ __export(exports_channel, {
|
|
|
48656
49666
|
function newestMessagesFirst(messages2) {
|
|
48657
49667
|
return [...messages2].sort((left, right) => right.createdAt - left.createdAt);
|
|
48658
49668
|
}
|
|
49669
|
+
function renderChannelMarkReadReport(report) {
|
|
49670
|
+
const message = report.lastReadMessageId ? ` through ${report.lastReadMessageId}` : "";
|
|
49671
|
+
return [
|
|
49672
|
+
`Marked ${report.conversationId} read for ${report.actorId}${message}.`,
|
|
49673
|
+
`Acknowledged deliveries: ${report.acknowledgedDeliveries}`
|
|
49674
|
+
].join(`
|
|
49675
|
+
`);
|
|
49676
|
+
}
|
|
48659
49677
|
function renderChannelCommandHelp() {
|
|
48660
49678
|
return [
|
|
48661
49679
|
"Usage: scout channel [--context-root <path>]",
|
|
48662
49680
|
" scout channel [<name>] --latest <count> [--json]",
|
|
49681
|
+
" scout channel [<name>] --mark-read [--json]",
|
|
48663
49682
|
"",
|
|
48664
49683
|
"Run a Scout channel server over stdio.",
|
|
48665
49684
|
"Read recent channel messages with --latest and exit.",
|
|
49685
|
+
"Mark a channel read with --mark-read (aliases: --read, --clear).",
|
|
48666
49686
|
"",
|
|
48667
49687
|
"Examples:",
|
|
48668
49688
|
" scout channel --latest 10 --json",
|
|
48669
49689
|
" scout channel homepage-polish --latest 10 --json",
|
|
49690
|
+
" scout channel shared --mark-read",
|
|
49691
|
+
" scout channel triage --clear",
|
|
48670
49692
|
"",
|
|
48671
49693
|
"This command is intended to be launched by Claude Code as a channel.",
|
|
48672
49694
|
"It subscribes to the Scout broker event stream and pushes incoming",
|
|
@@ -48683,7 +49705,7 @@ function renderChannelCommandHelp() {
|
|
|
48683
49705
|
"",
|
|
48684
49706
|
"Do not name this server scout if you also use the full Scout MCP server.",
|
|
48685
49707
|
"The channel server only exposes scout_send/scout_reply; scout mcp exposes",
|
|
48686
|
-
"agents_start,
|
|
49708
|
+
"ask, agents_start, invocations_get, invocations_wait, and the rest of the coordination tools."
|
|
48687
49709
|
].join(`
|
|
48688
49710
|
`);
|
|
48689
49711
|
}
|
|
@@ -48701,6 +49723,22 @@ async function runChannelCommand(context, args) {
|
|
|
48701
49723
|
context.output.writeValue(newestMessagesFirst(messages2), renderScoutMessageList);
|
|
48702
49724
|
return;
|
|
48703
49725
|
}
|
|
49726
|
+
if (options.markRead) {
|
|
49727
|
+
const actorId = await resolveScoutSenderId(null, options.currentDirectory, context.env);
|
|
49728
|
+
const result = await markScoutConversationRead({
|
|
49729
|
+
channel: options.channel,
|
|
49730
|
+
actorId,
|
|
49731
|
+
metadata: { source: "scout-cli", action: "channel.mark-read" }
|
|
49732
|
+
});
|
|
49733
|
+
const report = {
|
|
49734
|
+
conversationId: scoutConversationIdForChannel(options.channel),
|
|
49735
|
+
actorId,
|
|
49736
|
+
lastReadMessageId: result.cursor.lastReadMessageId ?? null,
|
|
49737
|
+
acknowledgedDeliveries: result.acknowledgedDeliveries
|
|
49738
|
+
};
|
|
49739
|
+
context.output.writeValue(report, renderChannelMarkReadReport);
|
|
49740
|
+
return;
|
|
49741
|
+
}
|
|
48704
49742
|
await runScoutChannelServer({
|
|
48705
49743
|
defaultCurrentDirectory: options.currentDirectory,
|
|
48706
49744
|
env: context.env
|
|
@@ -48721,34 +49759,39 @@ __export(exports_config, {
|
|
|
48721
49759
|
});
|
|
48722
49760
|
async function runConfigCommand(_context, args) {
|
|
48723
49761
|
const [subcommand, key, ...rest] = args;
|
|
48724
|
-
if (subcommand === "set" && key === "name" && rest.length > 0) {
|
|
48725
|
-
const
|
|
49762
|
+
if (subcommand === "set" && (key === "name" || key === "handle") && rest.length > 0) {
|
|
49763
|
+
const value = rest.join(" ").trim();
|
|
48726
49764
|
const config2 = loadUserConfig();
|
|
48727
|
-
config2
|
|
49765
|
+
config2[key] = value;
|
|
48728
49766
|
saveUserConfig(config2);
|
|
48729
|
-
console.log(
|
|
49767
|
+
console.log(`${key === "name" ? "Name" : "Handle"} set to: ${value}`);
|
|
48730
49768
|
return;
|
|
48731
49769
|
}
|
|
48732
|
-
if (subcommand === "get" && key === "name") {
|
|
48733
|
-
console.log(resolveOperatorName());
|
|
49770
|
+
if (subcommand === "get" && (key === "name" || key === "handle")) {
|
|
49771
|
+
console.log(key === "name" ? resolveOperatorName() : resolveOperatorHandle());
|
|
48734
49772
|
return;
|
|
48735
49773
|
}
|
|
48736
|
-
if (subcommand === "set" && key === "name") {
|
|
49774
|
+
if (subcommand === "set" && (key === "name" || key === "handle")) {
|
|
48737
49775
|
const config2 = loadUserConfig();
|
|
48738
|
-
delete config2
|
|
49776
|
+
delete config2[key];
|
|
48739
49777
|
saveUserConfig(config2);
|
|
48740
|
-
|
|
49778
|
+
const fallback = key === "name" ? resolveOperatorName() : resolveOperatorHandle();
|
|
49779
|
+
console.log(`${key === "name" ? "Name" : "Handle"} reset to default: ${fallback}`);
|
|
48741
49780
|
return;
|
|
48742
49781
|
}
|
|
48743
49782
|
if (!subcommand || subcommand === "show") {
|
|
48744
49783
|
const config2 = loadUserConfig();
|
|
48745
49784
|
const name = resolveOperatorName();
|
|
49785
|
+
const handle = resolveOperatorHandle();
|
|
48746
49786
|
console.log(`name: ${name}${config2.name ? "" : " (default)"}`);
|
|
49787
|
+
console.log(`handle: @${handle}${config2.handle ? "" : " (default)"}`);
|
|
48747
49788
|
return;
|
|
48748
49789
|
}
|
|
48749
49790
|
console.error("usage: scout config [show]");
|
|
48750
49791
|
console.error(" scout config set name <value>");
|
|
49792
|
+
console.error(" scout config set handle <value>");
|
|
48751
49793
|
console.error(" scout config get name");
|
|
49794
|
+
console.error(" scout config get handle");
|
|
48752
49795
|
process.exit(1);
|
|
48753
49796
|
}
|
|
48754
49797
|
var init_config = __esm(() => {
|
|
@@ -52087,7 +53130,7 @@ var init_mcp = __esm(() => {
|
|
|
52087
53130
|
|
|
52088
53131
|
// ../../apps/desktop/src/core/mcp/scout-mcp.ts
|
|
52089
53132
|
import { readFileSync as readFileSync10 } from "fs";
|
|
52090
|
-
import { basename as
|
|
53133
|
+
import { basename as basename12, resolve as resolve13 } from "path";
|
|
52091
53134
|
function createAgentPickerFieldMeta(input) {
|
|
52092
53135
|
return {
|
|
52093
53136
|
kind: "agent-picker",
|
|
@@ -52245,7 +53288,7 @@ function renderMcpAskSummary(result) {
|
|
|
52245
53288
|
].filter(Boolean);
|
|
52246
53289
|
const detailText = details.length > 0 ? `; ${details.join(", ")}` : "";
|
|
52247
53290
|
const followText = result.followUrl ? ` Follow: ${result.followUrl}` : "";
|
|
52248
|
-
if (result.waitStatus === "
|
|
53291
|
+
if (result.waitStatus === "pending" && result.flightId) {
|
|
52249
53292
|
const state = result.flight?.state ? ` ${result.flight.state}` : "";
|
|
52250
53293
|
return `Ask dispatch is still${state}; use invocations_wait with flightId=${result.flightId}.${followText}`;
|
|
52251
53294
|
}
|
|
@@ -52266,7 +53309,8 @@ function renderMcpAskPrimitiveSummary(receipt) {
|
|
|
52266
53309
|
const target = receipt.ids.targetAgentId ? ` to ${receipt.ids.targetAgentId}` : "";
|
|
52267
53310
|
const flight = receipt.ids.flightId ? `; flight ${receipt.ids.flightId}` : "";
|
|
52268
53311
|
const work = receipt.ids.workId ? `; work ${receipt.ids.workId}` : "";
|
|
52269
|
-
|
|
53312
|
+
const delivery = receipt.delivery === "mcp_notification" ? receipt.notification?.status === "scheduled" ? " Reply will be delivered by MCP notification." : receipt.ids.flightId ? ` MCP notification was not scheduled; use invocations_wait with flightId=${receipt.ids.flightId}.` : " MCP notification was not scheduled." : "";
|
|
53313
|
+
return `Ask ${receipt.state}${target}${flight}${work}.${delivery}`;
|
|
52270
53314
|
}
|
|
52271
53315
|
if (receipt.next) {
|
|
52272
53316
|
return `Ask was not sent: ${receipt.next.reason}`;
|
|
@@ -52282,6 +53326,9 @@ function resolveAskReplyMode(input) {
|
|
|
52282
53326
|
}
|
|
52283
53327
|
return input.awaitReply ? "inline" : "none";
|
|
52284
53328
|
}
|
|
53329
|
+
function resolveMcpReplyToSessionId(explicitSessionId, env) {
|
|
53330
|
+
return explicitSessionId?.trim() || env.CODEX_THREAD_ID?.trim() || undefined;
|
|
53331
|
+
}
|
|
52285
53332
|
function workUrlFor(workItem, env) {
|
|
52286
53333
|
return workItem ? buildScoutPath2(resolveScoutWebOrigin2(env), `/work/${encodeURIComponent(workItem.id)}`) : null;
|
|
52287
53334
|
}
|
|
@@ -52326,7 +53373,7 @@ function buildScoutFollowArtifacts(input, env) {
|
|
|
52326
53373
|
invocationId: input.flight?.invocationId ?? null,
|
|
52327
53374
|
conversationId: input.conversationId,
|
|
52328
53375
|
workId: input.workItem?.id ?? null,
|
|
52329
|
-
sessionId: null,
|
|
53376
|
+
sessionId: input.targetSessionId ?? null,
|
|
52330
53377
|
targetAgentId: input.targetAgentId ?? input.flight?.targetAgentId ?? null
|
|
52331
53378
|
};
|
|
52332
53379
|
const origin = resolveScoutWebOrigin2(env);
|
|
@@ -52347,6 +53394,12 @@ function buildScoutFollowArtifacts(input, env) {
|
|
|
52347
53394
|
function isTerminalFlightState2(state) {
|
|
52348
53395
|
return state === "completed" || state === "failed" || state === "cancelled";
|
|
52349
53396
|
}
|
|
53397
|
+
async function loadInvocationLifecycleForFlight(input) {
|
|
53398
|
+
if (!input.flight?.invocationId || !input.deps.getInvocationLifecycle) {
|
|
53399
|
+
return null;
|
|
53400
|
+
}
|
|
53401
|
+
return await input.deps.getInvocationLifecycle(input.brokerUrl, input.flight.invocationId);
|
|
53402
|
+
}
|
|
52350
53403
|
function isAcknowledgedFlightState(state) {
|
|
52351
53404
|
return state === "running" || state === "waiting";
|
|
52352
53405
|
}
|
|
@@ -52367,7 +53420,7 @@ async function waitForFlightForMcp(input) {
|
|
|
52367
53420
|
return { flight: latestFlight, waitStatus: "acknowledged" };
|
|
52368
53421
|
}
|
|
52369
53422
|
if (deadline !== null && Date.now() > deadline) {
|
|
52370
|
-
return { flight: latestFlight, waitStatus: "
|
|
53423
|
+
return { flight: latestFlight, waitStatus: "pending" };
|
|
52371
53424
|
}
|
|
52372
53425
|
latestFlight = await input.deps.getFlight(input.brokerUrl, input.flight.id) ?? latestFlight;
|
|
52373
53426
|
await new Promise((resolve14) => setTimeout(resolve14, 1000));
|
|
@@ -52378,9 +53431,9 @@ function buildInvocationLookupContent(input) {
|
|
|
52378
53431
|
flight: input.flight,
|
|
52379
53432
|
conversationId: null,
|
|
52380
53433
|
workItem: null,
|
|
52381
|
-
targetAgentId: input.flight?.targetAgentId ?? null
|
|
53434
|
+
targetAgentId: input.lifecycle?.targetAgentId ?? input.flight?.targetAgentId ?? null
|
|
52382
53435
|
}, input.env);
|
|
52383
|
-
const terminal = isTerminalFlightState2(input.flight?.state);
|
|
53436
|
+
const terminal = isTerminalFlightState2(input.flight?.state) || Boolean(input.lifecycle?.terminal);
|
|
52384
53437
|
return {
|
|
52385
53438
|
currentDirectory: input.currentDirectory,
|
|
52386
53439
|
flightId: input.flightId,
|
|
@@ -52388,8 +53441,9 @@ function buildInvocationLookupContent(input) {
|
|
|
52388
53441
|
waitStatus: input.waitStatus,
|
|
52389
53442
|
terminal,
|
|
52390
53443
|
flight: input.flight,
|
|
52391
|
-
|
|
52392
|
-
|
|
53444
|
+
lifecycle: input.lifecycle ?? null,
|
|
53445
|
+
output: input.flight?.output ?? input.flight?.summary ?? input.lifecycle?.terminal?.summary ?? null,
|
|
53446
|
+
error: input.flight?.error ?? input.lifecycle?.terminal?.errorClass ?? null,
|
|
52393
53447
|
ids: followArtifacts.ids,
|
|
52394
53448
|
links: followArtifacts.links,
|
|
52395
53449
|
followUrl: followArtifacts.followUrl
|
|
@@ -52406,7 +53460,7 @@ function renderInvocationLookupSummary(result) {
|
|
|
52406
53460
|
return result.error;
|
|
52407
53461
|
}
|
|
52408
53462
|
const followText = result.followUrl ? ` Follow: ${result.followUrl}` : "";
|
|
52409
|
-
if (result.waitStatus === "
|
|
53463
|
+
if (result.waitStatus === "pending") {
|
|
52410
53464
|
return `Flight ${result.flightId} is still ${result.flight.state}.${followText}`;
|
|
52411
53465
|
}
|
|
52412
53466
|
return `Flight ${result.flightId} is ${result.flight.state}.${followText}`;
|
|
@@ -52457,7 +53511,7 @@ function sendScoutReplyNotification(server, params) {
|
|
|
52457
53511
|
function scheduleScoutReplyNotification(input) {
|
|
52458
53512
|
(async () => {
|
|
52459
53513
|
try {
|
|
52460
|
-
const completedFlight = await input.deps.waitForFlight(input.brokerUrl, input.flight.id
|
|
53514
|
+
const completedFlight = await input.deps.waitForFlight(input.brokerUrl, input.flight.id);
|
|
52461
53515
|
await sendScoutReplyNotification(input.server, {
|
|
52462
53516
|
...input.context,
|
|
52463
53517
|
status: "completed",
|
|
@@ -52619,7 +53673,7 @@ function isCanonicalOpenScoutProjectRoot(projectRoot) {
|
|
|
52619
53673
|
if (!projectRoot) {
|
|
52620
53674
|
return false;
|
|
52621
53675
|
}
|
|
52622
|
-
return normalizeSearchValue(
|
|
53676
|
+
return normalizeSearchValue(basename12(resolve13(projectRoot))) === "openscout";
|
|
52623
53677
|
}
|
|
52624
53678
|
function isSameProjectRoot(left, right) {
|
|
52625
53679
|
if (!left || !right) {
|
|
@@ -52765,7 +53819,8 @@ function decorateAgentLabels(entries) {
|
|
|
52765
53819
|
workspace: entry.workspace,
|
|
52766
53820
|
node: entry.node,
|
|
52767
53821
|
projectRoot: entry.projectRoot,
|
|
52768
|
-
transport: entry.transport
|
|
53822
|
+
transport: entry.transport,
|
|
53823
|
+
sessionId: entry.sessionId
|
|
52769
53824
|
};
|
|
52770
53825
|
});
|
|
52771
53826
|
}
|
|
@@ -52826,7 +53881,7 @@ function scoreAgentCandidate(candidate, query) {
|
|
|
52826
53881
|
candidate.model,
|
|
52827
53882
|
candidate.workspace,
|
|
52828
53883
|
candidate.node,
|
|
52829
|
-
candidate.projectRoot ?
|
|
53884
|
+
candidate.projectRoot ? basename12(candidate.projectRoot) : null
|
|
52830
53885
|
];
|
|
52831
53886
|
let best = -1;
|
|
52832
53887
|
for (const value of haystacks) {
|
|
@@ -52883,6 +53938,7 @@ async function loadScoutAgentDirectory(currentDirectory) {
|
|
|
52883
53938
|
node: entry.node ?? existing.node,
|
|
52884
53939
|
projectRoot: entry.projectRoot ?? existing.projectRoot,
|
|
52885
53940
|
transport: entry.transport ?? existing.transport,
|
|
53941
|
+
sessionId: entry.sessionId ?? existing.sessionId,
|
|
52886
53942
|
state: rankState(entry.state) >= rankState(existing.state) ? entry.state : existing.state,
|
|
52887
53943
|
registrationKind: entry.registrationKind === "broker" ? entry.registrationKind : existing.registrationKind,
|
|
52888
53944
|
routable: entry.routable || existing.routable
|
|
@@ -52906,7 +53962,8 @@ async function loadScoutAgentDirectory(currentDirectory) {
|
|
|
52906
53962
|
workspace: discovered.instance.workspaceQualifier || null,
|
|
52907
53963
|
node: discovered.instance.nodeQualifier || null,
|
|
52908
53964
|
projectRoot: discovered.projectRoot,
|
|
52909
|
-
transport: discovered.runtime.transport ?? null
|
|
53965
|
+
transport: discovered.runtime.transport ?? null,
|
|
53966
|
+
sessionId: null
|
|
52910
53967
|
});
|
|
52911
53968
|
}
|
|
52912
53969
|
for (const agent of Object.values(broker.snapshot.agents ?? {})) {
|
|
@@ -52933,7 +53990,8 @@ async function loadScoutAgentDirectory(currentDirectory) {
|
|
|
52933
53990
|
workspace: normalizedStringOrNull(agent.workspaceQualifier),
|
|
52934
53991
|
node: normalizedStringOrNull(agent.nodeQualifier),
|
|
52935
53992
|
projectRoot: normalizedStringOrNull(preferredEndpoint?.projectRoot ?? preferredEndpoint?.cwd),
|
|
52936
|
-
transport: normalizedStringOrNull(preferredEndpoint?.transport)
|
|
53993
|
+
transport: normalizedStringOrNull(preferredEndpoint?.transport),
|
|
53994
|
+
sessionId: normalizedStringOrNull(preferredEndpoint?.sessionId)
|
|
52937
53995
|
});
|
|
52938
53996
|
}
|
|
52939
53997
|
return [...directory.values()].sort((left, right) => {
|
|
@@ -53038,7 +54096,9 @@ function defaultScoutMcpDependencies(env) {
|
|
|
53038
54096
|
reasoningEffort,
|
|
53039
54097
|
permissionProfile,
|
|
53040
54098
|
currentDirectory,
|
|
53041
|
-
createdById
|
|
54099
|
+
createdById,
|
|
54100
|
+
oneTimeUse,
|
|
54101
|
+
ttlMs
|
|
53042
54102
|
}) => createScoutAgentCard({
|
|
53043
54103
|
projectPath,
|
|
53044
54104
|
agentName,
|
|
@@ -53048,7 +54108,9 @@ function defaultScoutMcpDependencies(env) {
|
|
|
53048
54108
|
reasoningEffort,
|
|
53049
54109
|
permissionProfile,
|
|
53050
54110
|
currentDirectory,
|
|
53051
|
-
createdById
|
|
54111
|
+
createdById,
|
|
54112
|
+
oneTimeUse,
|
|
54113
|
+
ttlMs
|
|
53052
54114
|
}),
|
|
53053
54115
|
startAgent: ({
|
|
53054
54116
|
projectPath,
|
|
@@ -53146,6 +54208,7 @@ function defaultScoutMcpDependencies(env) {
|
|
|
53146
54208
|
channel,
|
|
53147
54209
|
shouldSpeak,
|
|
53148
54210
|
labels,
|
|
54211
|
+
replyToSessionId,
|
|
53149
54212
|
currentDirectory,
|
|
53150
54213
|
source
|
|
53151
54214
|
}) => askScoutQuestion({
|
|
@@ -53156,6 +54219,7 @@ function defaultScoutMcpDependencies(env) {
|
|
|
53156
54219
|
channel,
|
|
53157
54220
|
shouldSpeak,
|
|
53158
54221
|
labels,
|
|
54222
|
+
replyToSessionId,
|
|
53159
54223
|
currentDirectory,
|
|
53160
54224
|
source
|
|
53161
54225
|
}),
|
|
@@ -53167,6 +54231,7 @@ function defaultScoutMcpDependencies(env) {
|
|
|
53167
54231
|
channel,
|
|
53168
54232
|
shouldSpeak,
|
|
53169
54233
|
labels,
|
|
54234
|
+
replyToSessionId,
|
|
53170
54235
|
currentDirectory,
|
|
53171
54236
|
source
|
|
53172
54237
|
}) => askScoutAgentById({
|
|
@@ -53177,12 +54242,37 @@ function defaultScoutMcpDependencies(env) {
|
|
|
53177
54242
|
channel,
|
|
53178
54243
|
shouldSpeak,
|
|
53179
54244
|
labels,
|
|
54245
|
+
replyToSessionId,
|
|
54246
|
+
currentDirectory,
|
|
54247
|
+
source
|
|
54248
|
+
}),
|
|
54249
|
+
askSessionById: ({
|
|
54250
|
+
senderId,
|
|
54251
|
+
targetSessionId,
|
|
54252
|
+
body,
|
|
54253
|
+
workItem,
|
|
54254
|
+
channel,
|
|
54255
|
+
shouldSpeak,
|
|
54256
|
+
labels,
|
|
54257
|
+
replyToSessionId,
|
|
54258
|
+
currentDirectory,
|
|
54259
|
+
source
|
|
54260
|
+
}) => askScoutSessionById({
|
|
54261
|
+
senderId,
|
|
54262
|
+
targetSessionId,
|
|
54263
|
+
body,
|
|
54264
|
+
workItem,
|
|
54265
|
+
channel,
|
|
54266
|
+
shouldSpeak,
|
|
54267
|
+
labels,
|
|
54268
|
+
replyToSessionId,
|
|
53180
54269
|
currentDirectory,
|
|
53181
54270
|
source
|
|
53182
54271
|
}),
|
|
53183
54272
|
updateWorkItem: (input) => updateScoutWorkItem(input),
|
|
53184
54273
|
waitForFlight: (baseUrl, flightId, options) => waitForScoutFlight(baseUrl, flightId, options),
|
|
53185
54274
|
getFlight: (baseUrl, flightId) => loadScoutFlight(baseUrl, flightId),
|
|
54275
|
+
getInvocationLifecycle: (baseUrl, invocationId) => loadScoutInvocationLifecycle(baseUrl, invocationId),
|
|
53186
54276
|
readLabelBrief: (label, baseUrl) => readScoutLabelBrief(label, baseUrl),
|
|
53187
54277
|
readLabelFeed: (label, baseUrl, options) => readScoutLabelFeed(label, options, baseUrl)
|
|
53188
54278
|
};
|
|
@@ -53413,7 +54503,7 @@ function createScoutMcpServer(options) {
|
|
|
53413
54503
|
});
|
|
53414
54504
|
server.registerTool("messages_reply", {
|
|
53415
54505
|
title: "Reply to Scout Message",
|
|
53416
|
-
description: "Reply
|
|
54506
|
+
description: "Reply in an existing Scout conversation/thread. This is a normal threaded conversation message, not a fresh ask or owned-work lifecycle. If conversationId and replyToMessageId are omitted, this uses the current ScoutReplyContext. If there is no active context, use messages_send for a new message or ask for a new request.",
|
|
53417
54507
|
inputSchema: object2({
|
|
53418
54508
|
body: string2().min(1),
|
|
53419
54509
|
currentDirectory: string2().optional(),
|
|
@@ -53454,7 +54544,7 @@ function createScoutMcpServer(options) {
|
|
|
53454
54544
|
routingError: "missing_reply_context"
|
|
53455
54545
|
};
|
|
53456
54546
|
return {
|
|
53457
|
-
content: createPlainTextContent("No active Scout broker reply context. Use messages_send for a new message, or pass conversationId and replyToMessageId explicitly."),
|
|
54547
|
+
content: createPlainTextContent("No active Scout broker reply context. Use messages_send for a new message, use ask for a new request, or pass conversationId and replyToMessageId explicitly."),
|
|
53458
54548
|
structuredContent: structuredContent2
|
|
53459
54549
|
};
|
|
53460
54550
|
}
|
|
@@ -53527,7 +54617,7 @@ function createScoutMcpServer(options) {
|
|
|
53527
54617
|
});
|
|
53528
54618
|
server.registerTool("card_create", {
|
|
53529
54619
|
title: "Create Scout Agent Card",
|
|
53530
|
-
description: "Create a
|
|
54620
|
+
description: "Create a Scout agent card with a reply-ready return address. Agent-created cards default to one-time use so short-lived review/probe identities do not crowd the system; pass oneTimeUse=false for a persistent card. One target stays private by default; group coordination still requires an explicit channel elsewhere.",
|
|
53531
54621
|
inputSchema: object2({
|
|
53532
54622
|
projectPath: string2().optional(),
|
|
53533
54623
|
currentDirectory: string2().optional(),
|
|
@@ -53537,7 +54627,9 @@ function createScoutMcpServer(options) {
|
|
|
53537
54627
|
harness: _enum2(LOCAL_AGENT_HARNESS_VALUES).optional(),
|
|
53538
54628
|
model: string2().optional(),
|
|
53539
54629
|
reasoningEffort: string2().optional(),
|
|
53540
|
-
permissionProfile: string2().optional()
|
|
54630
|
+
permissionProfile: string2().optional(),
|
|
54631
|
+
oneTimeUse: boolean2().optional(),
|
|
54632
|
+
ttlSeconds: number2().positive().optional()
|
|
53541
54633
|
}),
|
|
53542
54634
|
outputSchema: cardCreateResultSchema,
|
|
53543
54635
|
annotations: {
|
|
@@ -53555,7 +54647,9 @@ function createScoutMcpServer(options) {
|
|
|
53555
54647
|
harness,
|
|
53556
54648
|
model,
|
|
53557
54649
|
reasoningEffort,
|
|
53558
|
-
permissionProfile
|
|
54650
|
+
permissionProfile,
|
|
54651
|
+
oneTimeUse,
|
|
54652
|
+
ttlSeconds
|
|
53559
54653
|
}) => {
|
|
53560
54654
|
const resolvedCurrentDirectory = resolveToolCurrentDirectory(currentDirectory, options.defaultCurrentDirectory);
|
|
53561
54655
|
const resolvedSenderId = await resolveMcpSenderId(deps, senderId, resolvedCurrentDirectory, env);
|
|
@@ -53568,7 +54662,9 @@ function createScoutMcpServer(options) {
|
|
|
53568
54662
|
reasoningEffort: reasoningEffort?.trim() || undefined,
|
|
53569
54663
|
permissionProfile: permissionProfile?.trim() || undefined,
|
|
53570
54664
|
currentDirectory: resolvedCurrentDirectory,
|
|
53571
|
-
createdById: resolvedSenderId
|
|
54665
|
+
createdById: resolvedSenderId,
|
|
54666
|
+
oneTimeUse: oneTimeUse ?? true,
|
|
54667
|
+
ttlMs: ttlSeconds === undefined ? undefined : Math.round(ttlSeconds * 1000)
|
|
53572
54668
|
});
|
|
53573
54669
|
const structuredContent = {
|
|
53574
54670
|
currentDirectory: resolvedCurrentDirectory,
|
|
@@ -53679,7 +54775,7 @@ function createScoutMcpServer(options) {
|
|
|
53679
54775
|
title: "Resolve Scout Agent",
|
|
53680
54776
|
description: "Resolve one exact Scout agent handle or return ambiguity details. Use this when a short handle may be ambiguous; explicit target sends can let the broker resolve in one call.",
|
|
53681
54777
|
inputSchema: object2({
|
|
53682
|
-
label: string2().min(1).describe("Scout agent handle or selector, such as @talkie
|
|
54778
|
+
label: string2().min(1).describe("Scout agent handle or selector, such as @talkie. Use harness/model/profile qualifiers only when you need a specific instance."),
|
|
53683
54779
|
currentDirectory: string2().optional()
|
|
53684
54780
|
}),
|
|
53685
54781
|
outputSchema: resolveResultSchema,
|
|
@@ -53710,17 +54806,25 @@ function createScoutMcpServer(options) {
|
|
|
53710
54806
|
});
|
|
53711
54807
|
server.registerTool("ask", {
|
|
53712
54808
|
title: "Ask",
|
|
53713
|
-
description: "Ask another agent to answer, review, try, build, compare, or give feedback. This is the
|
|
54809
|
+
description: "Ask another agent to answer, review, try, build, compare, or give feedback. This is the single broker front door for requested work: pass who to ask in `to`, pass `projectPath` when you know the project root and want Scout to choose/create the concrete instance, or pass `targetSessionId` to keep a sticky session. Ask may create message, invocation, flight, delivery, and work records as side effects; use invocations_get/invocations_wait to observe flight records. Use discovery tools only when you need broker help rather than agent work.",
|
|
53714
54810
|
inputSchema: object2({
|
|
53715
54811
|
to: string2().min(1).optional().describe("Agent id, label, sibling, specialist, or recent collaborator."),
|
|
53716
|
-
|
|
54812
|
+
targetSessionId: targetSessionIdInputSchema,
|
|
54813
|
+
projectPath: projectPathInputSchema,
|
|
53717
54814
|
body: string2().min(1),
|
|
53718
54815
|
currentDirectory: string2().optional(),
|
|
53719
54816
|
senderId: string2().optional(),
|
|
54817
|
+
replyToSessionId: string2().optional().describe("Optional requester session that should receive the eventual reply. When omitted, Codex MCP uses the current CODEX_THREAD_ID when available."),
|
|
54818
|
+
labels: array(string2()).optional(),
|
|
54819
|
+
workItem: workItemInputSchema.optional(),
|
|
54820
|
+
channel: string2().optional(),
|
|
54821
|
+
shouldSpeak: boolean2().optional(),
|
|
54822
|
+
replyMode: _enum2(REPLY_MODE_VALUES).describe("Reply delivery mode: 'none' returns durable ids only, 'inline' waits briefly, and 'notify' returns quickly then emits notifications/scout/reply later.").optional(),
|
|
54823
|
+
timeoutSeconds: number2().int().min(1).optional().describe("Caller wait budget in seconds for inline waits only; it never cancels or fails the broker ask."),
|
|
53720
54824
|
harness: _enum2(LOCAL_AGENT_HARNESS_VALUES).optional(),
|
|
53721
54825
|
workspace: _enum2(["same", "new_worktree"]).optional(),
|
|
53722
54826
|
session: _enum2(["reuse", "new"]).optional(),
|
|
53723
|
-
wait: boolean2().optional()
|
|
54827
|
+
wait: boolean2().optional().describe("Compatibility alias for replyMode='inline'.")
|
|
53724
54828
|
}),
|
|
53725
54829
|
outputSchema: askReceiptSchema,
|
|
53726
54830
|
annotations: {
|
|
@@ -53738,10 +54842,18 @@ function createScoutMcpServer(options) {
|
|
|
53738
54842
|
})
|
|
53739
54843
|
}, async ({
|
|
53740
54844
|
to,
|
|
54845
|
+
targetSessionId,
|
|
53741
54846
|
projectPath,
|
|
53742
54847
|
body,
|
|
53743
54848
|
currentDirectory,
|
|
53744
54849
|
senderId,
|
|
54850
|
+
replyToSessionId,
|
|
54851
|
+
labels,
|
|
54852
|
+
workItem,
|
|
54853
|
+
channel,
|
|
54854
|
+
shouldSpeak,
|
|
54855
|
+
replyMode,
|
|
54856
|
+
timeoutSeconds,
|
|
53745
54857
|
harness,
|
|
53746
54858
|
workspace,
|
|
53747
54859
|
session,
|
|
@@ -53749,8 +54861,14 @@ function createScoutMcpServer(options) {
|
|
|
53749
54861
|
}) => {
|
|
53750
54862
|
const resolvedCurrentDirectory = resolveToolCurrentDirectory(currentDirectory, options.defaultCurrentDirectory);
|
|
53751
54863
|
const resolvedSenderId = await resolveMcpSenderId(deps, senderId, resolvedCurrentDirectory, env);
|
|
53752
|
-
const
|
|
53753
|
-
const
|
|
54864
|
+
const resolvedReplyToSessionId = resolveMcpReplyToSessionId(replyToSessionId, env);
|
|
54865
|
+
const resolvedReplyMode = resolveAskReplyMode({
|
|
54866
|
+
awaitReply: wait,
|
|
54867
|
+
replyMode
|
|
54868
|
+
});
|
|
54869
|
+
const targetSession = targetSessionId?.trim();
|
|
54870
|
+
const targetTo = targetSession ? `session:${targetSession}` : to?.trim();
|
|
54871
|
+
const targetProjectPath = projectPath?.trim() ? resolve13(resolvedCurrentDirectory, projectPath.trim()) : undefined;
|
|
53754
54872
|
let structuredContent = targetTo && targetProjectPath ? {
|
|
53755
54873
|
ok: false,
|
|
53756
54874
|
state: "failed",
|
|
@@ -53763,15 +54881,20 @@ function createScoutMcpServer(options) {
|
|
|
53763
54881
|
senderId: resolvedSenderId,
|
|
53764
54882
|
...targetProjectPath ? { projectPath: targetProjectPath } : { to: targetTo ?? "" },
|
|
53765
54883
|
body,
|
|
53766
|
-
harness,
|
|
53767
|
-
workspace,
|
|
53768
|
-
session,
|
|
54884
|
+
...harness ? { harness } : {},
|
|
54885
|
+
...workspace ? { workspace } : {},
|
|
54886
|
+
...session ? { session } : {},
|
|
54887
|
+
...workItem ? { workItem } : {},
|
|
54888
|
+
...labels ? { labels } : {},
|
|
54889
|
+
...channel ? { channel } : {},
|
|
54890
|
+
...shouldSpeak !== undefined ? { shouldSpeak } : {},
|
|
54891
|
+
...resolvedReplyToSessionId ? { replyToSessionId: resolvedReplyToSessionId } : {},
|
|
53769
54892
|
currentDirectory: resolvedCurrentDirectory,
|
|
53770
54893
|
source: "scout-mcp"
|
|
53771
54894
|
});
|
|
53772
|
-
if (
|
|
54895
|
+
if (resolvedReplyMode === "inline" && structuredContent.ids.flightId) {
|
|
53773
54896
|
try {
|
|
53774
|
-
const flight = await deps.waitForFlight(deps.resolveBrokerUrl(), structuredContent.ids.flightId);
|
|
54897
|
+
const flight = await deps.waitForFlight(deps.resolveBrokerUrl(), structuredContent.ids.flightId, timeoutSeconds ? { timeoutSeconds } : undefined);
|
|
53775
54898
|
structuredContent = {
|
|
53776
54899
|
...structuredContent,
|
|
53777
54900
|
state: flight.state === "completed" ? "completed" : flight.state === "failed" || flight.state === "cancelled" ? "failed" : "queued",
|
|
@@ -53784,6 +54907,58 @@ function createScoutMcpServer(options) {
|
|
|
53784
54907
|
}
|
|
53785
54908
|
};
|
|
53786
54909
|
} catch {}
|
|
54910
|
+
} else if (resolvedReplyMode === "notify" && structuredContent.ids.flightId) {
|
|
54911
|
+
const flight = await deps.getFlight(deps.resolveBrokerUrl(), structuredContent.ids.flightId).catch(() => null);
|
|
54912
|
+
if (flight) {
|
|
54913
|
+
const followArtifacts = buildScoutFollowArtifacts({
|
|
54914
|
+
flight,
|
|
54915
|
+
conversationId: structuredContent.ids.conversationId ?? null,
|
|
54916
|
+
workItem: null,
|
|
54917
|
+
targetAgentId: structuredContent.ids.targetAgentId ?? flight.targetAgentId ?? null
|
|
54918
|
+
}, env);
|
|
54919
|
+
scheduleScoutReplyNotification({
|
|
54920
|
+
server,
|
|
54921
|
+
deps,
|
|
54922
|
+
brokerUrl: deps.resolveBrokerUrl(),
|
|
54923
|
+
flight,
|
|
54924
|
+
context: {
|
|
54925
|
+
currentDirectory: resolvedCurrentDirectory,
|
|
54926
|
+
senderId: resolvedSenderId,
|
|
54927
|
+
targetAgentId: structuredContent.ids.targetAgentId ?? flight.targetAgentId ?? null,
|
|
54928
|
+
targetLabel: targetTo ?? targetProjectPath ?? null,
|
|
54929
|
+
conversationId: structuredContent.ids.conversationId ?? null,
|
|
54930
|
+
messageId: structuredContent.ids.messageId ?? null,
|
|
54931
|
+
bindingRef: structuredContent.ids.bindingRef ? `ref:${structuredContent.ids.bindingRef}` : null,
|
|
54932
|
+
flightId: flight.id,
|
|
54933
|
+
workItem: null,
|
|
54934
|
+
workId: structuredContent.ids.workId ?? null,
|
|
54935
|
+
workUrl: null,
|
|
54936
|
+
ids: followArtifacts.ids,
|
|
54937
|
+
links: followArtifacts.links,
|
|
54938
|
+
followUrl: followArtifacts.followUrl
|
|
54939
|
+
}
|
|
54940
|
+
});
|
|
54941
|
+
structuredContent = {
|
|
54942
|
+
...structuredContent,
|
|
54943
|
+
delivery: "mcp_notification",
|
|
54944
|
+
notification: {
|
|
54945
|
+
method: "notifications/scout/reply",
|
|
54946
|
+
status: "scheduled"
|
|
54947
|
+
}
|
|
54948
|
+
};
|
|
54949
|
+
}
|
|
54950
|
+
}
|
|
54951
|
+
if (structuredContent.ok && !structuredContent.delivery) {
|
|
54952
|
+
structuredContent = {
|
|
54953
|
+
...structuredContent,
|
|
54954
|
+
delivery: resolvedReplyMode === "notify" ? "mcp_notification" : resolvedReplyMode === "inline" ? "inline" : "none",
|
|
54955
|
+
...resolvedReplyMode === "notify" ? {
|
|
54956
|
+
notification: {
|
|
54957
|
+
method: "notifications/scout/reply",
|
|
54958
|
+
status: "not_scheduled"
|
|
54959
|
+
}
|
|
54960
|
+
} : {}
|
|
54961
|
+
};
|
|
53787
54962
|
}
|
|
53788
54963
|
return {
|
|
53789
54964
|
content: createPlainTextContent(renderMcpAskPrimitiveSummary(structuredContent)),
|
|
@@ -53792,7 +54967,7 @@ function createScoutMcpServer(options) {
|
|
|
53792
54967
|
});
|
|
53793
54968
|
server.registerTool("messages_send", {
|
|
53794
54969
|
title: "Send Scout Message",
|
|
53795
|
-
description: "Post a broker-backed Scout
|
|
54970
|
+
description: "Post a broker-backed Scout message/update/reply. Use this for heads-up, threaded conversation, and status when no new owned-work lifecycle is needed. Pass targets as fields: one explicit target without a channel becomes a DM, group delivery requires an explicit channel, and the body remains payload text. Targeted DMs are dispatched by the broker when the target can be reached; callers should not preflight wake/session mechanics. Use targetAgentId when agents_start returned exactTargetAgentId; this bypasses label resolution. Use channel='shared' only for shared updates. Pass targetLabel for the single-call broker-resolved path; mentionAgentIds remains available for exact-id compatibility. If a requested new or precise target is unresolved or mismatched, call agents_start and retry with the returned exactTargetAgentId instead of substituting a different agent. For new agent-to-agent work, use ask instead.",
|
|
53796
54971
|
inputSchema: object2({
|
|
53797
54972
|
body: string2().min(1),
|
|
53798
54973
|
currentDirectory: string2().optional(),
|
|
@@ -54048,272 +55223,380 @@ function createScoutMcpServer(options) {
|
|
|
54048
55223
|
structuredContent
|
|
54049
55224
|
};
|
|
54050
55225
|
});
|
|
54051
|
-
|
|
54052
|
-
|
|
54053
|
-
|
|
54054
|
-
|
|
54055
|
-
|
|
54056
|
-
|
|
54057
|
-
|
|
54058
|
-
|
|
54059
|
-
|
|
54060
|
-
|
|
54061
|
-
|
|
54062
|
-
|
|
54063
|
-
|
|
54064
|
-
|
|
54065
|
-
|
|
54066
|
-
|
|
54067
|
-
|
|
54068
|
-
|
|
54069
|
-
|
|
54070
|
-
|
|
54071
|
-
|
|
54072
|
-
|
|
54073
|
-
readOnlyHint: false,
|
|
54074
|
-
idempotentHint: false,
|
|
54075
|
-
destructiveHint: false,
|
|
54076
|
-
openWorldHint: false
|
|
54077
|
-
},
|
|
54078
|
-
_meta: createToolUiMeta({
|
|
54079
|
-
targetAgentId: createAgentPickerFieldMeta({
|
|
54080
|
-
selection: "single",
|
|
54081
|
-
valueField: "agentId"
|
|
55226
|
+
if (env.OPENSCOUT_EXPOSE_DEPRECATED_INVOCATIONS_ASK === "1") {
|
|
55227
|
+
server.registerTool("invocations_ask", {
|
|
55228
|
+
title: "Deprecated Scout Invocation Ask",
|
|
55229
|
+
description: "DEPRECATED compatibility surface. Do not use this as an agent front door; use ask to talk to the broker. Ask creates broker invocation and flight records as side effects, then use invocations_get or invocations_wait to observe those records. This tool is hidden unless OPENSCOUT_EXPOSE_DEPRECATED_INVOCATIONS_ASK=1 is set for an older client.",
|
|
55230
|
+
inputSchema: object2({
|
|
55231
|
+
body: string2().min(1),
|
|
55232
|
+
currentDirectory: string2().optional(),
|
|
55233
|
+
senderId: string2().optional(),
|
|
55234
|
+
targetSessionId: targetSessionIdInputSchema,
|
|
55235
|
+
targetAgentId: targetAgentIdInputSchema,
|
|
55236
|
+
targetLabel: targetLabelInputSchema,
|
|
55237
|
+
replyToSessionId: string2().describe("Optional requester session that should receive the eventual reply. When omitted, Codex MCP uses the current CODEX_THREAD_ID when available.").optional(),
|
|
55238
|
+
labels: array(string2()).optional(),
|
|
55239
|
+
workItem: workItemInputSchema.optional(),
|
|
55240
|
+
channel: string2().optional(),
|
|
55241
|
+
shouldSpeak: boolean2().optional(),
|
|
55242
|
+
awaitReply: boolean2().describe("Compatibility alias for replyMode='inline'.").optional(),
|
|
55243
|
+
replyMode: _enum2(REPLY_MODE_VALUES).describe("Reply delivery mode: 'inline' returns a quick acknowledgement or immediate completion, 'notify' returns immediately then emits notifications/scout/reply, and 'none' returns durable ids only. Inline acknowledgement waits use timeoutSeconds only as a caller wait budget.").optional(),
|
|
55244
|
+
timeoutSeconds: number2().int().min(1).optional().describe("Caller wait budget in seconds for inline waits only; it never cancels or fails the broker ask.")
|
|
55245
|
+
}).refine((value) => Boolean(value.targetSessionId?.trim() || value.targetAgentId?.trim() || value.targetLabel?.trim()), {
|
|
55246
|
+
message: "Provide targetSessionId, targetAgentId, or targetLabel.",
|
|
55247
|
+
path: ["targetSessionId"]
|
|
54082
55248
|
}),
|
|
54083
|
-
|
|
54084
|
-
|
|
54085
|
-
|
|
54086
|
-
|
|
55249
|
+
outputSchema: askResultSchema,
|
|
55250
|
+
annotations: {
|
|
55251
|
+
readOnlyHint: false,
|
|
55252
|
+
idempotentHint: false,
|
|
55253
|
+
destructiveHint: false,
|
|
55254
|
+
openWorldHint: false
|
|
55255
|
+
},
|
|
55256
|
+
_meta: createToolUiMeta({
|
|
55257
|
+
targetSessionId: createAgentPickerFieldMeta({
|
|
55258
|
+
selection: "single",
|
|
55259
|
+
valueField: "sessionId"
|
|
55260
|
+
}),
|
|
55261
|
+
targetAgentId: createAgentPickerFieldMeta({
|
|
55262
|
+
selection: "single",
|
|
55263
|
+
valueField: "agentId"
|
|
55264
|
+
}),
|
|
55265
|
+
targetLabel: createAgentPickerFieldMeta({
|
|
55266
|
+
selection: "single",
|
|
55267
|
+
valueField: "label",
|
|
55268
|
+
resolveTool: "agents_resolve"
|
|
55269
|
+
})
|
|
54087
55270
|
})
|
|
54088
|
-
}
|
|
54089
|
-
|
|
54090
|
-
|
|
54091
|
-
|
|
54092
|
-
|
|
54093
|
-
|
|
54094
|
-
|
|
54095
|
-
|
|
54096
|
-
|
|
54097
|
-
|
|
54098
|
-
|
|
54099
|
-
|
|
54100
|
-
|
|
54101
|
-
|
|
54102
|
-
|
|
54103
|
-
|
|
54104
|
-
|
|
54105
|
-
|
|
54106
|
-
|
|
54107
|
-
|
|
54108
|
-
const
|
|
55271
|
+
}, async ({
|
|
55272
|
+
body,
|
|
55273
|
+
currentDirectory,
|
|
55274
|
+
senderId,
|
|
55275
|
+
targetSessionId,
|
|
55276
|
+
targetAgentId,
|
|
55277
|
+
targetLabel,
|
|
55278
|
+
replyToSessionId,
|
|
55279
|
+
labels,
|
|
55280
|
+
workItem,
|
|
55281
|
+
channel,
|
|
55282
|
+
shouldSpeak,
|
|
55283
|
+
awaitReply,
|
|
55284
|
+
replyMode,
|
|
55285
|
+
timeoutSeconds
|
|
55286
|
+
}) => {
|
|
55287
|
+
const resolvedCurrentDirectory = resolveToolCurrentDirectory(currentDirectory, options.defaultCurrentDirectory);
|
|
55288
|
+
const resolvedSenderId = await resolveMcpSenderId(deps, senderId, resolvedCurrentDirectory, env);
|
|
55289
|
+
const resolvedReplyMode = resolveAskReplyMode({ awaitReply, replyMode });
|
|
55290
|
+
const shouldAwait = resolvedReplyMode === "inline";
|
|
55291
|
+
const resolvedReplyToSessionId = resolveMcpReplyToSessionId(replyToSessionId, env);
|
|
55292
|
+
if (targetSessionId?.trim()) {
|
|
55293
|
+
const trimmedTargetSessionId = targetSessionId.trim();
|
|
55294
|
+
const result2 = await deps.askSessionById({
|
|
55295
|
+
senderId: resolvedSenderId,
|
|
55296
|
+
targetSessionId: trimmedTargetSessionId,
|
|
55297
|
+
body,
|
|
55298
|
+
workItem,
|
|
55299
|
+
channel,
|
|
55300
|
+
shouldSpeak,
|
|
55301
|
+
labels,
|
|
55302
|
+
replyToSessionId: resolvedReplyToSessionId,
|
|
55303
|
+
currentDirectory: resolvedCurrentDirectory,
|
|
55304
|
+
source: "scout-mcp"
|
|
55305
|
+
});
|
|
55306
|
+
const waitResult2 = shouldAwait ? await waitForFlightForMcp({
|
|
55307
|
+
deps,
|
|
55308
|
+
brokerUrl: deps.resolveBrokerUrl(),
|
|
55309
|
+
flight: result2.flight ?? null,
|
|
55310
|
+
timeoutSeconds
|
|
55311
|
+
}) : { flight: null, waitStatus: "not_requested" };
|
|
55312
|
+
const completedFlight2 = waitResult2.flight;
|
|
55313
|
+
const trackedWorkItem2 = result2.workItem ?? null;
|
|
55314
|
+
const notificationScheduled2 = resolvedReplyMode === "notify" && Boolean(result2.flight);
|
|
55315
|
+
const followArtifacts2 = buildScoutFollowArtifacts({
|
|
55316
|
+
flight: completedFlight2 ?? result2.flight ?? null,
|
|
55317
|
+
conversationId: result2.conversationId ?? null,
|
|
55318
|
+
workItem: trackedWorkItem2,
|
|
55319
|
+
targetSessionId: trimmedTargetSessionId,
|
|
55320
|
+
targetAgentId: result2.flight?.targetAgentId ?? null
|
|
55321
|
+
}, env);
|
|
55322
|
+
if (resolvedReplyMode === "notify" && result2.flight) {
|
|
55323
|
+
scheduleScoutReplyNotification({
|
|
55324
|
+
server,
|
|
55325
|
+
deps,
|
|
55326
|
+
brokerUrl: deps.resolveBrokerUrl(),
|
|
55327
|
+
flight: result2.flight,
|
|
55328
|
+
context: {
|
|
55329
|
+
currentDirectory: resolvedCurrentDirectory,
|
|
55330
|
+
senderId: resolvedSenderId,
|
|
55331
|
+
targetAgentId: result2.flight.targetAgentId ?? null,
|
|
55332
|
+
targetLabel: null,
|
|
55333
|
+
conversationId: result2.conversationId ?? null,
|
|
55334
|
+
messageId: result2.messageId ?? null,
|
|
55335
|
+
flightId: result2.flight.id,
|
|
55336
|
+
workItem: trackedWorkItem2,
|
|
55337
|
+
workId: trackedWorkItem2?.id ?? null,
|
|
55338
|
+
workUrl: workUrlFor(trackedWorkItem2, env),
|
|
55339
|
+
ids: followArtifacts2.ids,
|
|
55340
|
+
links: followArtifacts2.links,
|
|
55341
|
+
followUrl: followArtifacts2.followUrl
|
|
55342
|
+
}
|
|
55343
|
+
});
|
|
55344
|
+
}
|
|
55345
|
+
const unresolvedTargetId = result2.unresolvedTargetId ?? null;
|
|
55346
|
+
const structuredContent2 = {
|
|
55347
|
+
currentDirectory: resolvedCurrentDirectory,
|
|
55348
|
+
senderId: resolvedSenderId,
|
|
55349
|
+
targetAgentId: result2.flight?.targetAgentId ?? null,
|
|
55350
|
+
targetSessionId: trimmedTargetSessionId,
|
|
55351
|
+
targetLabel: null,
|
|
55352
|
+
replyToSessionId: resolvedReplyToSessionId ?? null,
|
|
55353
|
+
usedBroker: result2.usedBroker,
|
|
55354
|
+
awaited: shouldAwait,
|
|
55355
|
+
waitStatus: waitResult2.waitStatus,
|
|
55356
|
+
replyMode: resolvedReplyMode,
|
|
55357
|
+
delivery: notificationScheduled2 ? "mcp_notification" : shouldAwait ? "inline" : "none",
|
|
55358
|
+
notification: resolvedReplyMode === "notify" ? {
|
|
55359
|
+
method: "notifications/scout/reply",
|
|
55360
|
+
status: notificationScheduled2 ? "scheduled" : "not_scheduled"
|
|
55361
|
+
} : null,
|
|
55362
|
+
conversationId: result2.conversationId ?? null,
|
|
55363
|
+
messageId: result2.messageId ?? null,
|
|
55364
|
+
flight: completedFlight2 ?? result2.flight ?? null,
|
|
55365
|
+
flightId: completedFlight2?.id ?? result2.flight?.id ?? null,
|
|
55366
|
+
output: waitResult2.waitStatus === "completed" || waitResult2.waitStatus === "terminal" ? completedFlight2?.output ?? completedFlight2?.summary ?? null : null,
|
|
55367
|
+
unresolvedTargetId,
|
|
55368
|
+
unresolvedTargetLabel: null,
|
|
55369
|
+
workItem: trackedWorkItem2,
|
|
55370
|
+
workId: trackedWorkItem2?.id ?? null,
|
|
55371
|
+
workUrl: workUrlFor(trackedWorkItem2, env),
|
|
55372
|
+
ids: followArtifacts2.ids,
|
|
55373
|
+
links: followArtifacts2.links,
|
|
55374
|
+
followUrl: followArtifacts2.followUrl,
|
|
55375
|
+
targetDiagnostic: result2.targetDiagnostic ?? buildExactTargetIdsDiagnostic(unresolvedTargetId ? [unresolvedTargetId] : []),
|
|
55376
|
+
startSuggestion: null
|
|
55377
|
+
};
|
|
55378
|
+
return {
|
|
55379
|
+
content: createPlainTextContent(renderMcpAskSummary(structuredContent2)),
|
|
55380
|
+
structuredContent: structuredContent2
|
|
55381
|
+
};
|
|
55382
|
+
}
|
|
55383
|
+
if (targetAgentId?.trim()) {
|
|
55384
|
+
const result2 = await deps.askAgentById({
|
|
55385
|
+
senderId: resolvedSenderId,
|
|
55386
|
+
targetAgentId: targetAgentId.trim(),
|
|
55387
|
+
body,
|
|
55388
|
+
workItem,
|
|
55389
|
+
channel,
|
|
55390
|
+
shouldSpeak,
|
|
55391
|
+
labels,
|
|
55392
|
+
replyToSessionId: resolvedReplyToSessionId,
|
|
55393
|
+
currentDirectory: resolvedCurrentDirectory,
|
|
55394
|
+
source: "scout-mcp"
|
|
55395
|
+
});
|
|
55396
|
+
const waitResult2 = shouldAwait ? await waitForFlightForMcp({
|
|
55397
|
+
deps,
|
|
55398
|
+
brokerUrl: deps.resolveBrokerUrl(),
|
|
55399
|
+
flight: result2.flight ?? null,
|
|
55400
|
+
timeoutSeconds
|
|
55401
|
+
}) : { flight: null, waitStatus: "not_requested" };
|
|
55402
|
+
const completedFlight2 = waitResult2.flight;
|
|
55403
|
+
const trackedWorkItem2 = result2.workItem ?? null;
|
|
55404
|
+
const notificationScheduled2 = resolvedReplyMode === "notify" && Boolean(result2.flight);
|
|
55405
|
+
const followArtifacts2 = buildScoutFollowArtifacts({
|
|
55406
|
+
flight: completedFlight2 ?? result2.flight ?? null,
|
|
55407
|
+
conversationId: result2.conversationId ?? null,
|
|
55408
|
+
workItem: trackedWorkItem2,
|
|
55409
|
+
targetAgentId: targetAgentId.trim()
|
|
55410
|
+
}, env);
|
|
55411
|
+
if (resolvedReplyMode === "notify" && result2.flight) {
|
|
55412
|
+
scheduleScoutReplyNotification({
|
|
55413
|
+
server,
|
|
55414
|
+
deps,
|
|
55415
|
+
brokerUrl: deps.resolveBrokerUrl(),
|
|
55416
|
+
flight: result2.flight,
|
|
55417
|
+
context: {
|
|
55418
|
+
currentDirectory: resolvedCurrentDirectory,
|
|
55419
|
+
senderId: resolvedSenderId,
|
|
55420
|
+
targetAgentId: targetAgentId.trim(),
|
|
55421
|
+
targetLabel: null,
|
|
55422
|
+
conversationId: result2.conversationId ?? null,
|
|
55423
|
+
messageId: result2.messageId ?? null,
|
|
55424
|
+
flightId: result2.flight.id,
|
|
55425
|
+
workItem: trackedWorkItem2,
|
|
55426
|
+
workId: trackedWorkItem2?.id ?? null,
|
|
55427
|
+
workUrl: workUrlFor(trackedWorkItem2, env),
|
|
55428
|
+
ids: followArtifacts2.ids,
|
|
55429
|
+
links: followArtifacts2.links,
|
|
55430
|
+
followUrl: followArtifacts2.followUrl
|
|
55431
|
+
}
|
|
55432
|
+
});
|
|
55433
|
+
}
|
|
55434
|
+
const unresolvedTargetId = result2.unresolvedTargetId ?? null;
|
|
55435
|
+
const structuredContent2 = {
|
|
55436
|
+
currentDirectory: resolvedCurrentDirectory,
|
|
55437
|
+
senderId: resolvedSenderId,
|
|
55438
|
+
targetAgentId: targetAgentId.trim(),
|
|
55439
|
+
targetSessionId: null,
|
|
55440
|
+
targetLabel: null,
|
|
55441
|
+
replyToSessionId: resolvedReplyToSessionId ?? null,
|
|
55442
|
+
usedBroker: result2.usedBroker,
|
|
55443
|
+
awaited: shouldAwait,
|
|
55444
|
+
waitStatus: waitResult2.waitStatus,
|
|
55445
|
+
replyMode: resolvedReplyMode,
|
|
55446
|
+
delivery: notificationScheduled2 ? "mcp_notification" : shouldAwait ? "inline" : "none",
|
|
55447
|
+
notification: resolvedReplyMode === "notify" ? {
|
|
55448
|
+
method: "notifications/scout/reply",
|
|
55449
|
+
status: notificationScheduled2 ? "scheduled" : "not_scheduled"
|
|
55450
|
+
} : null,
|
|
55451
|
+
conversationId: result2.conversationId ?? null,
|
|
55452
|
+
messageId: result2.messageId ?? null,
|
|
55453
|
+
flight: completedFlight2 ?? result2.flight ?? null,
|
|
55454
|
+
flightId: completedFlight2?.id ?? result2.flight?.id ?? null,
|
|
55455
|
+
output: waitResult2.waitStatus === "completed" || waitResult2.waitStatus === "terminal" ? completedFlight2?.output ?? completedFlight2?.summary ?? null : null,
|
|
55456
|
+
unresolvedTargetId,
|
|
55457
|
+
unresolvedTargetLabel: null,
|
|
55458
|
+
workItem: trackedWorkItem2,
|
|
55459
|
+
workId: trackedWorkItem2?.id ?? null,
|
|
55460
|
+
workUrl: workUrlFor(trackedWorkItem2, env),
|
|
55461
|
+
ids: followArtifacts2.ids,
|
|
55462
|
+
links: followArtifacts2.links,
|
|
55463
|
+
followUrl: followArtifacts2.followUrl,
|
|
55464
|
+
targetDiagnostic: result2.targetDiagnostic ?? buildExactTargetIdsDiagnostic(unresolvedTargetId ? [unresolvedTargetId] : []),
|
|
55465
|
+
startSuggestion: null
|
|
55466
|
+
};
|
|
55467
|
+
return {
|
|
55468
|
+
content: createPlainTextContent(renderMcpAskSummary(structuredContent2)),
|
|
55469
|
+
structuredContent: structuredContent2
|
|
55470
|
+
};
|
|
55471
|
+
}
|
|
55472
|
+
const targetCheck = await diagnosePreciseTargetLabel({
|
|
55473
|
+
deps,
|
|
55474
|
+
targetLabel,
|
|
55475
|
+
currentDirectory: resolvedCurrentDirectory
|
|
55476
|
+
});
|
|
55477
|
+
if (targetCheck.blocked) {
|
|
55478
|
+
const structuredContent2 = {
|
|
55479
|
+
currentDirectory: resolvedCurrentDirectory,
|
|
55480
|
+
senderId: resolvedSenderId,
|
|
55481
|
+
targetAgentId: null,
|
|
55482
|
+
targetSessionId: null,
|
|
55483
|
+
targetLabel: targetLabel.trim(),
|
|
55484
|
+
replyToSessionId: resolvedReplyToSessionId ?? null,
|
|
55485
|
+
usedBroker: true,
|
|
55486
|
+
awaited: shouldAwait,
|
|
55487
|
+
waitStatus: "not_requested",
|
|
55488
|
+
replyMode: resolvedReplyMode,
|
|
55489
|
+
delivery: "none",
|
|
55490
|
+
notification: null,
|
|
55491
|
+
conversationId: null,
|
|
55492
|
+
messageId: null,
|
|
55493
|
+
flight: null,
|
|
55494
|
+
flightId: null,
|
|
55495
|
+
output: null,
|
|
55496
|
+
unresolvedTargetId: null,
|
|
55497
|
+
unresolvedTargetLabel: targetLabel.trim(),
|
|
55498
|
+
workItem: null,
|
|
55499
|
+
workId: null,
|
|
55500
|
+
workUrl: null,
|
|
55501
|
+
targetDiagnostic: targetCheck.diagnostic,
|
|
55502
|
+
startSuggestion: targetCheck.startSuggestion
|
|
55503
|
+
};
|
|
55504
|
+
return {
|
|
55505
|
+
content: createPlainTextContent(renderMcpAskSummary(structuredContent2)),
|
|
55506
|
+
structuredContent: structuredContent2
|
|
55507
|
+
};
|
|
55508
|
+
}
|
|
55509
|
+
const result = await deps.askQuestion({
|
|
54109
55510
|
senderId: resolvedSenderId,
|
|
54110
|
-
|
|
55511
|
+
targetLabel: targetLabel.trim(),
|
|
54111
55512
|
body,
|
|
54112
55513
|
workItem,
|
|
54113
55514
|
channel,
|
|
54114
55515
|
shouldSpeak,
|
|
54115
55516
|
labels,
|
|
55517
|
+
replyToSessionId: resolvedReplyToSessionId,
|
|
54116
55518
|
currentDirectory: resolvedCurrentDirectory,
|
|
54117
55519
|
source: "scout-mcp"
|
|
54118
55520
|
});
|
|
54119
|
-
const
|
|
55521
|
+
const waitResult = shouldAwait ? await waitForFlightForMcp({
|
|
54120
55522
|
deps,
|
|
54121
55523
|
brokerUrl: deps.resolveBrokerUrl(),
|
|
54122
|
-
flight:
|
|
55524
|
+
flight: result.flight ?? null,
|
|
54123
55525
|
timeoutSeconds
|
|
54124
55526
|
}) : { flight: null, waitStatus: "not_requested" };
|
|
54125
|
-
const
|
|
54126
|
-
const
|
|
54127
|
-
const
|
|
54128
|
-
const
|
|
54129
|
-
flight:
|
|
54130
|
-
conversationId:
|
|
54131
|
-
workItem:
|
|
54132
|
-
targetAgentId: targetAgentId
|
|
55527
|
+
const completedFlight = waitResult.flight;
|
|
55528
|
+
const trackedWorkItem = result.workItem ?? null;
|
|
55529
|
+
const notificationScheduled = resolvedReplyMode === "notify" && Boolean(result.flight);
|
|
55530
|
+
const followArtifacts = buildScoutFollowArtifacts({
|
|
55531
|
+
flight: completedFlight ?? result.flight ?? null,
|
|
55532
|
+
conversationId: result.conversationId ?? null,
|
|
55533
|
+
workItem: trackedWorkItem,
|
|
55534
|
+
targetAgentId: result.flight?.targetAgentId ?? null
|
|
54133
55535
|
}, env);
|
|
54134
|
-
if (resolvedReplyMode === "notify" &&
|
|
55536
|
+
if (resolvedReplyMode === "notify" && result.flight) {
|
|
54135
55537
|
scheduleScoutReplyNotification({
|
|
54136
55538
|
server,
|
|
54137
55539
|
deps,
|
|
54138
55540
|
brokerUrl: deps.resolveBrokerUrl(),
|
|
54139
|
-
flight:
|
|
54140
|
-
timeoutSeconds,
|
|
55541
|
+
flight: result.flight,
|
|
54141
55542
|
context: {
|
|
54142
55543
|
currentDirectory: resolvedCurrentDirectory,
|
|
54143
55544
|
senderId: resolvedSenderId,
|
|
54144
|
-
targetAgentId: targetAgentId
|
|
54145
|
-
targetLabel:
|
|
54146
|
-
conversationId:
|
|
54147
|
-
messageId:
|
|
54148
|
-
|
|
54149
|
-
|
|
54150
|
-
|
|
54151
|
-
|
|
54152
|
-
|
|
54153
|
-
|
|
54154
|
-
|
|
55545
|
+
targetAgentId: result.flight.targetAgentId ?? null,
|
|
55546
|
+
targetLabel: targetLabel.trim(),
|
|
55547
|
+
conversationId: result.conversationId ?? null,
|
|
55548
|
+
messageId: result.messageId ?? null,
|
|
55549
|
+
bindingRef: result.bindingRef ? `ref:${result.bindingRef}` : null,
|
|
55550
|
+
flightId: result.flight.id,
|
|
55551
|
+
workItem: trackedWorkItem,
|
|
55552
|
+
workId: trackedWorkItem?.id ?? null,
|
|
55553
|
+
workUrl: workUrlFor(trackedWorkItem, env),
|
|
55554
|
+
ids: followArtifacts.ids,
|
|
55555
|
+
links: followArtifacts.links,
|
|
55556
|
+
followUrl: followArtifacts.followUrl
|
|
54155
55557
|
}
|
|
54156
55558
|
});
|
|
54157
55559
|
}
|
|
54158
|
-
const
|
|
54159
|
-
const
|
|
55560
|
+
const startSuggestion = result.unresolvedTarget ? await buildStartSuggestionForTarget(result.unresolvedTarget, resolvedCurrentDirectory) : null;
|
|
55561
|
+
const structuredContent = {
|
|
54160
55562
|
currentDirectory: resolvedCurrentDirectory,
|
|
54161
55563
|
senderId: resolvedSenderId,
|
|
54162
|
-
targetAgentId: targetAgentId
|
|
54163
|
-
|
|
54164
|
-
|
|
55564
|
+
targetAgentId: result.flight?.targetAgentId ?? null,
|
|
55565
|
+
targetSessionId: null,
|
|
55566
|
+
targetLabel: targetLabel.trim(),
|
|
55567
|
+
replyToSessionId: resolvedReplyToSessionId ?? null,
|
|
55568
|
+
usedBroker: result.usedBroker,
|
|
54165
55569
|
awaited: shouldAwait,
|
|
54166
|
-
waitStatus:
|
|
55570
|
+
waitStatus: waitResult.waitStatus,
|
|
54167
55571
|
replyMode: resolvedReplyMode,
|
|
54168
|
-
delivery:
|
|
55572
|
+
delivery: notificationScheduled ? "mcp_notification" : shouldAwait ? "inline" : "none",
|
|
54169
55573
|
notification: resolvedReplyMode === "notify" ? {
|
|
54170
55574
|
method: "notifications/scout/reply",
|
|
54171
|
-
status:
|
|
55575
|
+
status: notificationScheduled ? "scheduled" : "not_scheduled"
|
|
54172
55576
|
} : null,
|
|
54173
|
-
conversationId:
|
|
54174
|
-
messageId:
|
|
54175
|
-
|
|
54176
|
-
|
|
54177
|
-
|
|
54178
|
-
|
|
54179
|
-
unresolvedTargetLabel: null,
|
|
54180
|
-
workItem: trackedWorkItem2,
|
|
54181
|
-
workId: trackedWorkItem2?.id ?? null,
|
|
54182
|
-
workUrl: workUrlFor(trackedWorkItem2, env),
|
|
54183
|
-
ids: followArtifacts2.ids,
|
|
54184
|
-
links: followArtifacts2.links,
|
|
54185
|
-
followUrl: followArtifacts2.followUrl,
|
|
54186
|
-
targetDiagnostic: result2.targetDiagnostic ?? buildExactTargetIdsDiagnostic(unresolvedTargetId ? [unresolvedTargetId] : []),
|
|
54187
|
-
startSuggestion: null
|
|
54188
|
-
};
|
|
54189
|
-
return {
|
|
54190
|
-
content: createPlainTextContent(renderMcpAskSummary(structuredContent2)),
|
|
54191
|
-
structuredContent: structuredContent2
|
|
54192
|
-
};
|
|
54193
|
-
}
|
|
54194
|
-
const targetCheck = await diagnosePreciseTargetLabel({
|
|
54195
|
-
deps,
|
|
54196
|
-
targetLabel,
|
|
54197
|
-
currentDirectory: resolvedCurrentDirectory
|
|
54198
|
-
});
|
|
54199
|
-
if (targetCheck.blocked) {
|
|
54200
|
-
const structuredContent2 = {
|
|
54201
|
-
currentDirectory: resolvedCurrentDirectory,
|
|
54202
|
-
senderId: resolvedSenderId,
|
|
54203
|
-
targetAgentId: null,
|
|
54204
|
-
targetLabel: targetLabel.trim(),
|
|
54205
|
-
usedBroker: true,
|
|
54206
|
-
awaited: shouldAwait,
|
|
54207
|
-
waitStatus: "not_requested",
|
|
54208
|
-
replyMode: resolvedReplyMode,
|
|
54209
|
-
delivery: "none",
|
|
54210
|
-
notification: null,
|
|
54211
|
-
conversationId: null,
|
|
54212
|
-
messageId: null,
|
|
54213
|
-
flight: null,
|
|
54214
|
-
flightId: null,
|
|
54215
|
-
output: null,
|
|
55577
|
+
conversationId: result.conversationId ?? null,
|
|
55578
|
+
messageId: result.messageId ?? null,
|
|
55579
|
+
bindingRef: result.bindingRef ? `ref:${result.bindingRef}` : null,
|
|
55580
|
+
flight: completedFlight ?? result.flight ?? null,
|
|
55581
|
+
flightId: completedFlight?.id ?? result.flight?.id ?? null,
|
|
55582
|
+
output: waitResult.waitStatus === "completed" || waitResult.waitStatus === "terminal" ? completedFlight?.output ?? completedFlight?.summary ?? null : null,
|
|
54216
55583
|
unresolvedTargetId: null,
|
|
54217
|
-
unresolvedTargetLabel:
|
|
54218
|
-
workItem:
|
|
54219
|
-
workId: null,
|
|
54220
|
-
workUrl:
|
|
54221
|
-
|
|
54222
|
-
|
|
55584
|
+
unresolvedTargetLabel: result.unresolvedTarget ?? null,
|
|
55585
|
+
workItem: trackedWorkItem,
|
|
55586
|
+
workId: trackedWorkItem?.id ?? null,
|
|
55587
|
+
workUrl: workUrlFor(trackedWorkItem, env),
|
|
55588
|
+
ids: followArtifacts.ids,
|
|
55589
|
+
links: followArtifacts.links,
|
|
55590
|
+
followUrl: followArtifacts.followUrl,
|
|
55591
|
+
targetDiagnostic: result.targetDiagnostic ?? null,
|
|
55592
|
+
startSuggestion
|
|
54223
55593
|
};
|
|
54224
55594
|
return {
|
|
54225
|
-
content: createPlainTextContent(renderMcpAskSummary(
|
|
54226
|
-
structuredContent
|
|
55595
|
+
content: createPlainTextContent(renderMcpAskSummary(structuredContent)),
|
|
55596
|
+
structuredContent
|
|
54227
55597
|
};
|
|
54228
|
-
}
|
|
54229
|
-
const result = await deps.askQuestion({
|
|
54230
|
-
senderId: resolvedSenderId,
|
|
54231
|
-
targetLabel: targetLabel.trim(),
|
|
54232
|
-
body,
|
|
54233
|
-
workItem,
|
|
54234
|
-
channel,
|
|
54235
|
-
shouldSpeak,
|
|
54236
|
-
labels,
|
|
54237
|
-
currentDirectory: resolvedCurrentDirectory,
|
|
54238
|
-
source: "scout-mcp"
|
|
54239
55598
|
});
|
|
54240
|
-
|
|
54241
|
-
deps,
|
|
54242
|
-
brokerUrl: deps.resolveBrokerUrl(),
|
|
54243
|
-
flight: result.flight ?? null,
|
|
54244
|
-
timeoutSeconds
|
|
54245
|
-
}) : { flight: null, waitStatus: "not_requested" };
|
|
54246
|
-
const completedFlight = waitResult.flight;
|
|
54247
|
-
const trackedWorkItem = result.workItem ?? null;
|
|
54248
|
-
const notificationScheduled = resolvedReplyMode === "notify" && Boolean(result.flight);
|
|
54249
|
-
const followArtifacts = buildScoutFollowArtifacts({
|
|
54250
|
-
flight: completedFlight ?? result.flight ?? null,
|
|
54251
|
-
conversationId: result.conversationId ?? null,
|
|
54252
|
-
workItem: trackedWorkItem,
|
|
54253
|
-
targetAgentId: result.flight?.targetAgentId ?? null
|
|
54254
|
-
}, env);
|
|
54255
|
-
if (resolvedReplyMode === "notify" && result.flight) {
|
|
54256
|
-
scheduleScoutReplyNotification({
|
|
54257
|
-
server,
|
|
54258
|
-
deps,
|
|
54259
|
-
brokerUrl: deps.resolveBrokerUrl(),
|
|
54260
|
-
flight: result.flight,
|
|
54261
|
-
timeoutSeconds,
|
|
54262
|
-
context: {
|
|
54263
|
-
currentDirectory: resolvedCurrentDirectory,
|
|
54264
|
-
senderId: resolvedSenderId,
|
|
54265
|
-
targetAgentId: result.flight.targetAgentId ?? null,
|
|
54266
|
-
targetLabel: targetLabel.trim(),
|
|
54267
|
-
conversationId: result.conversationId ?? null,
|
|
54268
|
-
messageId: result.messageId ?? null,
|
|
54269
|
-
bindingRef: result.bindingRef ? `ref:${result.bindingRef}` : null,
|
|
54270
|
-
flightId: result.flight.id,
|
|
54271
|
-
workItem: trackedWorkItem,
|
|
54272
|
-
workId: trackedWorkItem?.id ?? null,
|
|
54273
|
-
workUrl: workUrlFor(trackedWorkItem, env),
|
|
54274
|
-
ids: followArtifacts.ids,
|
|
54275
|
-
links: followArtifacts.links,
|
|
54276
|
-
followUrl: followArtifacts.followUrl
|
|
54277
|
-
}
|
|
54278
|
-
});
|
|
54279
|
-
}
|
|
54280
|
-
const startSuggestion = result.unresolvedTarget ? await buildStartSuggestionForTarget(result.unresolvedTarget, resolvedCurrentDirectory) : null;
|
|
54281
|
-
const structuredContent = {
|
|
54282
|
-
currentDirectory: resolvedCurrentDirectory,
|
|
54283
|
-
senderId: resolvedSenderId,
|
|
54284
|
-
targetAgentId: result.flight?.targetAgentId ?? null,
|
|
54285
|
-
targetLabel: targetLabel.trim(),
|
|
54286
|
-
usedBroker: result.usedBroker,
|
|
54287
|
-
awaited: shouldAwait,
|
|
54288
|
-
waitStatus: waitResult.waitStatus,
|
|
54289
|
-
replyMode: resolvedReplyMode,
|
|
54290
|
-
delivery: notificationScheduled ? "mcp_notification" : shouldAwait ? "inline" : "none",
|
|
54291
|
-
notification: resolvedReplyMode === "notify" ? {
|
|
54292
|
-
method: "notifications/scout/reply",
|
|
54293
|
-
status: notificationScheduled ? "scheduled" : "not_scheduled"
|
|
54294
|
-
} : null,
|
|
54295
|
-
conversationId: result.conversationId ?? null,
|
|
54296
|
-
messageId: result.messageId ?? null,
|
|
54297
|
-
bindingRef: result.bindingRef ? `ref:${result.bindingRef}` : null,
|
|
54298
|
-
flight: completedFlight ?? result.flight ?? null,
|
|
54299
|
-
flightId: completedFlight?.id ?? result.flight?.id ?? null,
|
|
54300
|
-
output: waitResult.waitStatus === "completed" || waitResult.waitStatus === "terminal" ? completedFlight?.output ?? completedFlight?.summary ?? null : null,
|
|
54301
|
-
unresolvedTargetId: null,
|
|
54302
|
-
unresolvedTargetLabel: result.unresolvedTarget ?? null,
|
|
54303
|
-
workItem: trackedWorkItem,
|
|
54304
|
-
workId: trackedWorkItem?.id ?? null,
|
|
54305
|
-
workUrl: workUrlFor(trackedWorkItem, env),
|
|
54306
|
-
ids: followArtifacts.ids,
|
|
54307
|
-
links: followArtifacts.links,
|
|
54308
|
-
followUrl: followArtifacts.followUrl,
|
|
54309
|
-
targetDiagnostic: result.targetDiagnostic ?? null,
|
|
54310
|
-
startSuggestion
|
|
54311
|
-
};
|
|
54312
|
-
return {
|
|
54313
|
-
content: createPlainTextContent(renderMcpAskSummary(structuredContent)),
|
|
54314
|
-
structuredContent
|
|
54315
|
-
};
|
|
54316
|
-
});
|
|
55599
|
+
}
|
|
54317
55600
|
server.registerTool("invocations_get", {
|
|
54318
55601
|
title: "Get Scout Ask",
|
|
54319
55602
|
description: "Fetch the current broker flight state for a previously-created Scout ask or invocation. Use this with a flightId returned by ask to observe long-running work without blocking the original ask call.",
|
|
@@ -54331,11 +55614,18 @@ function createScoutMcpServer(options) {
|
|
|
54331
55614
|
}, async ({ currentDirectory, flightId }) => {
|
|
54332
55615
|
const resolvedCurrentDirectory = resolveToolCurrentDirectory(currentDirectory, options.defaultCurrentDirectory);
|
|
54333
55616
|
const trimmedFlightId = flightId.trim();
|
|
54334
|
-
const
|
|
55617
|
+
const brokerUrl = deps.resolveBrokerUrl();
|
|
55618
|
+
const flight = await deps.getFlight(brokerUrl, trimmedFlightId);
|
|
55619
|
+
const lifecycle2 = await loadInvocationLifecycleForFlight({
|
|
55620
|
+
deps,
|
|
55621
|
+
brokerUrl,
|
|
55622
|
+
flight
|
|
55623
|
+
});
|
|
54335
55624
|
const structuredContent = buildInvocationLookupContent({
|
|
54336
55625
|
currentDirectory: resolvedCurrentDirectory,
|
|
54337
55626
|
flightId: trimmedFlightId,
|
|
54338
55627
|
flight,
|
|
55628
|
+
lifecycle: lifecycle2,
|
|
54339
55629
|
waitStatus: "not_requested",
|
|
54340
55630
|
env
|
|
54341
55631
|
});
|
|
@@ -54350,7 +55640,7 @@ function createScoutMcpServer(options) {
|
|
|
54350
55640
|
inputSchema: object2({
|
|
54351
55641
|
currentDirectory: string2().optional(),
|
|
54352
55642
|
flightId: string2().min(1),
|
|
54353
|
-
timeoutSeconds: number2().int().min(1).max(300).default(30)
|
|
55643
|
+
timeoutSeconds: number2().int().min(1).max(300).default(30).describe("Caller wait budget in seconds; elapsed time returns the latest state and does not cancel or fail the ask.")
|
|
54354
55644
|
}),
|
|
54355
55645
|
outputSchema: invocationLookupResultSchema,
|
|
54356
55646
|
annotations: {
|
|
@@ -54362,23 +55652,30 @@ function createScoutMcpServer(options) {
|
|
|
54362
55652
|
}, async ({ currentDirectory, flightId, timeoutSeconds }) => {
|
|
54363
55653
|
const resolvedCurrentDirectory = resolveToolCurrentDirectory(currentDirectory, options.defaultCurrentDirectory);
|
|
54364
55654
|
const trimmedFlightId = flightId.trim();
|
|
55655
|
+
const brokerUrl = deps.resolveBrokerUrl();
|
|
54365
55656
|
let flight = null;
|
|
54366
|
-
let waitStatus = "
|
|
55657
|
+
let waitStatus = "pending";
|
|
54367
55658
|
try {
|
|
54368
|
-
flight = await deps.waitForFlight(
|
|
55659
|
+
flight = await deps.waitForFlight(brokerUrl, trimmedFlightId, { timeoutSeconds });
|
|
54369
55660
|
waitStatus = "completed";
|
|
54370
55661
|
} catch (error48) {
|
|
54371
|
-
flight = await deps.getFlight(
|
|
55662
|
+
flight = await deps.getFlight(brokerUrl, trimmedFlightId);
|
|
54372
55663
|
if (isTerminalFlightState2(flight?.state)) {
|
|
54373
55664
|
waitStatus = "terminal";
|
|
54374
55665
|
} else if (!(error48 instanceof Error) || !error48.message.includes("Timed out waiting for flight")) {
|
|
54375
55666
|
throw error48;
|
|
54376
55667
|
}
|
|
54377
55668
|
}
|
|
55669
|
+
const lifecycle2 = await loadInvocationLifecycleForFlight({
|
|
55670
|
+
deps,
|
|
55671
|
+
brokerUrl,
|
|
55672
|
+
flight
|
|
55673
|
+
});
|
|
54378
55674
|
const structuredContent = buildInvocationLookupContent({
|
|
54379
55675
|
currentDirectory: resolvedCurrentDirectory,
|
|
54380
55676
|
flightId: trimmedFlightId,
|
|
54381
55677
|
flight,
|
|
55678
|
+
lifecycle: lifecycle2,
|
|
54382
55679
|
waitStatus,
|
|
54383
55680
|
env
|
|
54384
55681
|
});
|
|
@@ -54545,7 +55842,7 @@ async function runScoutMcpServer(options) {
|
|
|
54545
55842
|
const transport = new StdioServerTransport;
|
|
54546
55843
|
await server.connect(transport);
|
|
54547
55844
|
}
|
|
54548
|
-
var AGENT_STATE_VALUES, REGISTRATION_KIND_VALUES, RESOLVE_KIND_VALUES, MESSAGE_ROUTE_KIND_VALUES, MESSAGE_ROUTING_ERROR_VALUES, REPLY_MODE_VALUES, REPLY_DELIVERY_VALUES, LOCAL_AGENT_HARNESS_VALUES, DEFAULT_ASK_ACK_TIMEOUT_SECONDS2 = 30, SCOUT_MCP_UI_META_KEY = "openscout/ui", scoutAgentToolIconMeta, scoutAgentAvatarMeta, targetLabelInputSchema, targetAgentIdInputSchema, mentionAgentIdsInputSchema, flightSchema, labelBriefFlightSchema, labelBriefWorkItemSchema, labelBriefSchema, labelFeedEventSchema, labelFeedSchema, trackedWorkItemSchema, workItemInputSchema, waitingOnSchema, progressSchema, workItemUpdateSchema, agentCandidateSchema, scoutReturnAddressSchema, scoutAgentCardSchema, localAgentStatusSchema, whoAmISchema, brokerMessageSchema, messagesInboxResultSchema, messagesChannelResultSchema, brokerFeedRecordSchema, brokerFeedItemSchema, brokerFeedSchema, searchResultSchema, resolveResultSchema, startSuggestionSchema, followIdsSchema, followLinksSchema, sendRoutingAdviceSchema, sendResultSchema, replyContextSchema, currentReplyContextResultSchema, replyResultSchema, cardCreateResultSchema, agentStartResultSchema, currentSessionAttachResultSchema, askResultSchema, askReceiptSchema, invocationLookupResultSchema, workUpdateResultSchema;
|
|
55845
|
+
var AGENT_STATE_VALUES, REGISTRATION_KIND_VALUES, RESOLVE_KIND_VALUES, MESSAGE_ROUTE_KIND_VALUES, MESSAGE_ROUTING_ERROR_VALUES, REPLY_MODE_VALUES, REPLY_DELIVERY_VALUES, LOCAL_AGENT_HARNESS_VALUES, DEFAULT_ASK_ACK_TIMEOUT_SECONDS2 = 30, SCOUT_MCP_UI_META_KEY = "openscout/ui", scoutAgentToolIconMeta, scoutAgentAvatarMeta, targetLabelInputSchema, targetAgentIdInputSchema, targetSessionIdInputSchema, projectPathInputSchema, mentionAgentIdsInputSchema, flightSchema, invocationLifecycleSchema, labelBriefFlightSchema, labelBriefWorkItemSchema, labelBriefSchema, labelFeedEventSchema, labelFeedSchema, trackedWorkItemSchema, workItemInputSchema, waitingOnSchema, progressSchema, workItemUpdateSchema, agentCandidateSchema, scoutReturnAddressSchema, scoutAgentCardLifecycleSchema, scoutAgentCardSchema, localAgentStatusSchema, whoAmISchema, brokerMessageSchema, messagesInboxResultSchema, messagesChannelResultSchema, brokerFeedRecordSchema, brokerFeedItemSchema, brokerFeedSchema, searchResultSchema, resolveResultSchema, startSuggestionSchema, followIdsSchema, followLinksSchema, sendRoutingAdviceSchema, sendResultSchema, replyContextSchema, currentReplyContextResultSchema, replyResultSchema, cardCreateResultSchema, agentStartResultSchema, currentSessionAttachResultSchema, askResultSchema, askReceiptSchema, invocationLookupResultSchema, workUpdateResultSchema;
|
|
54549
55846
|
var init_scout_mcp = __esm(() => {
|
|
54550
55847
|
init_mcp();
|
|
54551
55848
|
init_stdio2();
|
|
@@ -54590,8 +55887,10 @@ var init_scout_mcp = __esm(() => {
|
|
|
54590
55887
|
colorSeedField: "agentId",
|
|
54591
55888
|
fallbackGlyph: "@"
|
|
54592
55889
|
};
|
|
54593
|
-
targetLabelInputSchema = string2().describe("Scout agent handle to contact, such as @talkie
|
|
55890
|
+
targetLabelInputSchema = string2().describe("Scout agent handle to contact, such as @talkie. Treat harness/model/profile as instance constraints, not the base agent identity.").optional();
|
|
54594
55891
|
targetAgentIdInputSchema = string2().describe("Exact Scout agent id when already known, such as talkie.master.mini").optional();
|
|
55892
|
+
targetSessionIdInputSchema = string2().describe("Exact Scout session id to continue, such as a CODEX_THREAD_ID or attached runtime session id").optional();
|
|
55893
|
+
projectPathInputSchema = string2().min(1).describe("Project root to ask when you do not have a specific agent in mind; Scout resolves or creates the concrete agent instance.").optional();
|
|
54595
55894
|
mentionAgentIdsInputSchema = array(string2()).describe("Exact Scout agent ids to target directly when you already know them").optional();
|
|
54596
55895
|
flightSchema = object2({
|
|
54597
55896
|
id: string2(),
|
|
@@ -54607,6 +55906,26 @@ var init_scout_mcp = __esm(() => {
|
|
|
54607
55906
|
labels: array(string2()).optional(),
|
|
54608
55907
|
metadata: record(string2(), unknown()).optional()
|
|
54609
55908
|
});
|
|
55909
|
+
invocationLifecycleSchema = object2({
|
|
55910
|
+
invocationId: string2(),
|
|
55911
|
+
flightId: string2().optional(),
|
|
55912
|
+
state: string2(),
|
|
55913
|
+
targetAgentId: string2().optional(),
|
|
55914
|
+
targetEndpointId: string2().optional(),
|
|
55915
|
+
peerNodeId: string2().optional(),
|
|
55916
|
+
peerFlightId: string2().optional(),
|
|
55917
|
+
workId: string2().optional(),
|
|
55918
|
+
actionId: string2().optional(),
|
|
55919
|
+
idempotencyKey: string2().optional(),
|
|
55920
|
+
acknowledgedAt: number2().optional(),
|
|
55921
|
+
startedAt: number2().optional(),
|
|
55922
|
+
completedAt: number2().optional(),
|
|
55923
|
+
expiresAt: number2().optional(),
|
|
55924
|
+
lastProgressAt: number2().optional(),
|
|
55925
|
+
terminal: object2({}).catchall(unknown()).optional(),
|
|
55926
|
+
deliveries: array(object2({}).catchall(unknown())).optional(),
|
|
55927
|
+
metadata: record(string2(), unknown()).optional()
|
|
55928
|
+
}).catchall(unknown());
|
|
54610
55929
|
labelBriefFlightSchema = object2({
|
|
54611
55930
|
id: string2(),
|
|
54612
55931
|
invocationId: string2(),
|
|
@@ -54762,7 +56081,8 @@ var init_scout_mcp = __esm(() => {
|
|
|
54762
56081
|
workspace: string2().nullable(),
|
|
54763
56082
|
node: string2().nullable(),
|
|
54764
56083
|
projectRoot: string2().nullable(),
|
|
54765
|
-
transport: string2().nullable()
|
|
56084
|
+
transport: string2().nullable(),
|
|
56085
|
+
sessionId: string2().nullable().optional()
|
|
54766
56086
|
});
|
|
54767
56087
|
scoutReturnAddressSchema = object2({
|
|
54768
56088
|
actorId: string2(),
|
|
@@ -54777,6 +56097,14 @@ var init_scout_mcp = __esm(() => {
|
|
|
54777
56097
|
sessionId: string2().optional(),
|
|
54778
56098
|
metadata: record(string2(), unknown()).optional()
|
|
54779
56099
|
});
|
|
56100
|
+
scoutAgentCardLifecycleSchema = object2({
|
|
56101
|
+
kind: _enum2(["persistent", "one_time"]),
|
|
56102
|
+
createdAt: number2().optional(),
|
|
56103
|
+
createdById: string2().optional(),
|
|
56104
|
+
expiresAt: number2().optional(),
|
|
56105
|
+
maxUses: number2().optional(),
|
|
56106
|
+
inboxConversationId: string2().optional()
|
|
56107
|
+
});
|
|
54780
56108
|
scoutAgentCardSchema = object2({
|
|
54781
56109
|
id: string2(),
|
|
54782
56110
|
agentId: string2(),
|
|
@@ -54796,6 +56124,7 @@ var init_scout_mcp = __esm(() => {
|
|
|
54796
56124
|
createdById: string2().optional(),
|
|
54797
56125
|
brokerRegistered: boolean2(),
|
|
54798
56126
|
inboxConversationId: string2().optional(),
|
|
56127
|
+
lifecycle: scoutAgentCardLifecycleSchema.optional(),
|
|
54799
56128
|
returnAddress: scoutReturnAddressSchema,
|
|
54800
56129
|
metadata: record(string2(), unknown()).optional()
|
|
54801
56130
|
});
|
|
@@ -55077,10 +56406,12 @@ var init_scout_mcp = __esm(() => {
|
|
|
55077
56406
|
currentDirectory: string2(),
|
|
55078
56407
|
senderId: string2(),
|
|
55079
56408
|
targetAgentId: string2().nullable(),
|
|
56409
|
+
targetSessionId: string2().nullable().optional(),
|
|
55080
56410
|
targetLabel: string2().nullable(),
|
|
56411
|
+
replyToSessionId: string2().nullable().optional(),
|
|
55081
56412
|
usedBroker: boolean2(),
|
|
55082
56413
|
awaited: boolean2(),
|
|
55083
|
-
waitStatus: _enum2(["not_requested", "acknowledged", "completed", "terminal", "
|
|
56414
|
+
waitStatus: _enum2(["not_requested", "acknowledged", "completed", "terminal", "pending"]).optional(),
|
|
55084
56415
|
replyMode: _enum2(REPLY_MODE_VALUES).optional(),
|
|
55085
56416
|
delivery: _enum2(REPLY_DELIVERY_VALUES).optional(),
|
|
55086
56417
|
notification: object2({
|
|
@@ -55115,6 +56446,11 @@ var init_scout_mcp = __esm(() => {
|
|
|
55115
56446
|
workId: string2().optional(),
|
|
55116
56447
|
bindingRef: string2().optional()
|
|
55117
56448
|
}),
|
|
56449
|
+
delivery: _enum2(REPLY_DELIVERY_VALUES).optional(),
|
|
56450
|
+
notification: object2({
|
|
56451
|
+
method: literal("notifications/scout/reply"),
|
|
56452
|
+
status: _enum2(["scheduled", "not_scheduled"])
|
|
56453
|
+
}).optional(),
|
|
55118
56454
|
next: object2({
|
|
55119
56455
|
tool: _enum2(["agents_resolve", "agents_search", "agents_start"]),
|
|
55120
56456
|
arguments: record(string2(), unknown()),
|
|
@@ -55129,9 +56465,10 @@ var init_scout_mcp = __esm(() => {
|
|
|
55129
56465
|
currentDirectory: string2(),
|
|
55130
56466
|
flightId: string2(),
|
|
55131
56467
|
found: boolean2(),
|
|
55132
|
-
waitStatus: _enum2(["not_requested", "completed", "terminal", "
|
|
56468
|
+
waitStatus: _enum2(["not_requested", "completed", "terminal", "pending"]).optional(),
|
|
55133
56469
|
terminal: boolean2(),
|
|
55134
56470
|
flight: flightSchema.nullable(),
|
|
56471
|
+
lifecycle: invocationLifecycleSchema.nullable().optional(),
|
|
55135
56472
|
output: string2().nullable(),
|
|
55136
56473
|
error: string2().nullable(),
|
|
55137
56474
|
ids: followIdsSchema.optional(),
|
|
@@ -55489,14 +56826,13 @@ function renderMcpCommandHelp() {
|
|
|
55489
56826
|
" messages_channel read recent messages from a named channel",
|
|
55490
56827
|
" broker_feed native broker messages/status/errors for an agent",
|
|
55491
56828
|
" session_attach_current",
|
|
55492
|
-
" attach the current live Codex session
|
|
55493
|
-
" card_create fresh reply-ready return address",
|
|
55494
|
-
" agents_start start/create a concrete local agent session",
|
|
56829
|
+
" pro integration: attach the current live Codex session",
|
|
56830
|
+
" card_create pro integration: fresh reply-ready return address",
|
|
56831
|
+
" agents_start pro integration: start/create a concrete local agent session",
|
|
55495
56832
|
" agents_search find likely targets when routing is ambiguous",
|
|
55496
56833
|
" agents_resolve pin one exact target when needed",
|
|
55497
|
-
" ask agent-to-agent work
|
|
56834
|
+
" ask broker front door for agent-to-agent work/replies",
|
|
55498
56835
|
" messages_send tell / update with explicit target fields or channel",
|
|
55499
|
-
" invocations_ask low-level invocation compatibility surface",
|
|
55500
56836
|
" invocations_get fetch current state for an existing ask flight",
|
|
55501
56837
|
" invocations_wait bounded wait for an existing ask flight",
|
|
55502
56838
|
" work_update progress / waiting / review / done for existing work",
|
|
@@ -59527,6 +60863,14 @@ function sqlQuoteLiteral(value) {
|
|
|
59527
60863
|
function sqlStringList(values) {
|
|
59528
60864
|
return `(${values.map(sqlQuoteLiteral).join(",")})`;
|
|
59529
60865
|
}
|
|
60866
|
+
function sqlTimestampMsExpression(valueExpression) {
|
|
60867
|
+
return `CASE
|
|
60868
|
+
WHEN ${valueExpression} IS NULL THEN NULL
|
|
60869
|
+
WHEN CAST(${valueExpression} AS REAL) < ${EPOCH_MILLISECONDS_FLOOR}
|
|
60870
|
+
THEN CAST(CAST(${valueExpression} AS REAL) * 1000 AS INTEGER)
|
|
60871
|
+
ELSE CAST(${valueExpression} AS INTEGER)
|
|
60872
|
+
END`;
|
|
60873
|
+
}
|
|
59530
60874
|
function queryExecutingAgentIds() {
|
|
59531
60875
|
return new Set(db().prepare(`SELECT DISTINCT target_agent_id FROM flights
|
|
59532
60876
|
WHERE state = 'running'`).all().map((row) => row.target_agent_id));
|
|
@@ -59598,6 +60942,9 @@ function queryMobileAgents(limit = 50) {
|
|
|
59598
60942
|
});
|
|
59599
60943
|
}
|
|
59600
60944
|
function queryMobileSessions(limit = 50) {
|
|
60945
|
+
const conversationCreatedAtExpression = sqlTimestampMsExpression("c.created_at");
|
|
60946
|
+
const messageCreatedAtExpression = sqlTimestampMsExpression("created_at");
|
|
60947
|
+
const previewMessageCreatedAtExpression = sqlTimestampMsExpression("created_at");
|
|
59601
60948
|
const rows = db().prepare(`SELECT
|
|
59602
60949
|
c.id,
|
|
59603
60950
|
c.kind,
|
|
@@ -59605,12 +60952,12 @@ function queryMobileSessions(limit = 50) {
|
|
|
59605
60952
|
c.metadata_json
|
|
59606
60953
|
FROM conversations c
|
|
59607
60954
|
WHERE c.kind = 'direct'
|
|
59608
|
-
ORDER BY
|
|
60955
|
+
ORDER BY ${conversationCreatedAtExpression} DESC
|
|
59609
60956
|
LIMIT ?`).all(limit);
|
|
59610
60957
|
const memberStmt = db().prepare(`SELECT actor_id FROM conversation_members WHERE conversation_id = ?`);
|
|
59611
|
-
const statsStmt = db().prepare(`SELECT COUNT(*) AS cnt, MAX(
|
|
60958
|
+
const statsStmt = db().prepare(`SELECT COUNT(*) AS cnt, MAX(${messageCreatedAtExpression}) AS last_at FROM messages WHERE conversation_id = ?`);
|
|
59612
60959
|
const previewStmt = db().prepare(`SELECT body FROM messages WHERE conversation_id = ? AND actor_id != 'operator'
|
|
59613
|
-
ORDER BY
|
|
60960
|
+
ORDER BY ${previewMessageCreatedAtExpression} DESC LIMIT 1`);
|
|
59614
60961
|
return rows.map((r) => {
|
|
59615
60962
|
const participants = memberStmt.all(r.id).map((m) => m.actor_id);
|
|
59616
60963
|
const agentId = participants.find((p) => p !== "operator") ?? null;
|
|
@@ -59786,7 +61133,7 @@ var _db = null, HOME, LATEST_AGENT_ENDPOINT_JOIN = `LEFT JOIN agent_endpoints ep
|
|
|
59786
61133
|
WHERE ep2.agent_id = a.id
|
|
59787
61134
|
ORDER BY ep2.updated_at DESC
|
|
59788
61135
|
LIMIT 1
|
|
59789
|
-
)`, ACTIVE_FLIGHT_STATES_SQL, ACTIVE_FLIGHT_MAX_AGE_MS, ACTIVE_WORK_STATES_SQL;
|
|
61136
|
+
)`, ACTIVE_FLIGHT_STATES_SQL, ACTIVE_FLIGHT_MAX_AGE_MS, EPOCH_MILLISECONDS_FLOOR = 1000000000000, ACTIVE_WORK_STATES_SQL;
|
|
59790
61137
|
var init_db_queries = __esm(() => {
|
|
59791
61138
|
HOME = homedir23();
|
|
59792
61139
|
ACTIVE_FLIGHT_STATES_SQL = sqlStringList(["running", "waking", "waiting", "queued"]);
|
|
@@ -59795,7 +61142,7 @@ var init_db_queries = __esm(() => {
|
|
|
59795
61142
|
});
|
|
59796
61143
|
|
|
59797
61144
|
// ../../apps/desktop/src/core/mobile/service.ts
|
|
59798
|
-
import { basename as
|
|
61145
|
+
import { basename as basename13, resolve as resolve16 } from "path";
|
|
59799
61146
|
function normalizeTimestamp2(value) {
|
|
59800
61147
|
if (!value)
|
|
59801
61148
|
return null;
|
|
@@ -59810,6 +61157,27 @@ function metadataString4(metadata, key) {
|
|
|
59810
61157
|
const value = metadata?.[key];
|
|
59811
61158
|
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
59812
61159
|
}
|
|
61160
|
+
function metadataBoolean2(metadata, key) {
|
|
61161
|
+
return metadata?.[key] === true;
|
|
61162
|
+
}
|
|
61163
|
+
function isBrokerRequesterWaitTimeoutStatusMessage(message) {
|
|
61164
|
+
if (message.class !== "status" || metadataString4(message.metadata, "source") !== "broker") {
|
|
61165
|
+
return false;
|
|
61166
|
+
}
|
|
61167
|
+
return message.body.includes("Scout stopped waiting for a synchronous result") || message.body.includes("the requester stopped waiting after");
|
|
61168
|
+
}
|
|
61169
|
+
function isRequesterWaitTimeoutFlight(flight) {
|
|
61170
|
+
return metadataBoolean2(flight.metadata, "requesterTimedOut") || metadataString4(flight.metadata, "timeoutScope") === "requester_wait" || Boolean(flight.summary?.includes("Scout stopped waiting for a synchronous result"));
|
|
61171
|
+
}
|
|
61172
|
+
function isInactiveAgent(agent) {
|
|
61173
|
+
return metadataBoolean2(agent?.metadata, "retiredFromFleet") || metadataBoolean2(agent?.metadata, "staleLocalRegistration");
|
|
61174
|
+
}
|
|
61175
|
+
function isInactiveEndpoint(snapshot, endpoint) {
|
|
61176
|
+
if (!endpoint) {
|
|
61177
|
+
return true;
|
|
61178
|
+
}
|
|
61179
|
+
return metadataBoolean2(endpoint.metadata, "retiredFromFleet") || metadataBoolean2(endpoint.metadata, "staleLocalRegistration") || isInactiveAgent(snapshot.agents[endpoint.agentId]);
|
|
61180
|
+
}
|
|
59813
61181
|
function titleCaseToken(value) {
|
|
59814
61182
|
return value.length === 0 ? value : `${value[0].toUpperCase()}${value.slice(1)}`;
|
|
59815
61183
|
}
|
|
@@ -59864,6 +61232,9 @@ async function loadMobileWorkspaceInventory(currentDirectory) {
|
|
|
59864
61232
|
function latestMessageByConversation(snapshot) {
|
|
59865
61233
|
const buckets = new Map;
|
|
59866
61234
|
for (const message of Object.values(snapshot.messages)) {
|
|
61235
|
+
if (isBrokerRequesterWaitTimeoutStatusMessage(message)) {
|
|
61236
|
+
continue;
|
|
61237
|
+
}
|
|
59867
61238
|
const next = buckets.get(message.conversationId) ?? [];
|
|
59868
61239
|
next.push(message);
|
|
59869
61240
|
buckets.set(message.conversationId, next);
|
|
@@ -59882,14 +61253,14 @@ function agentDisplayName(snapshot, agentId) {
|
|
|
59882
61253
|
return snapshot.agents[agentId]?.displayName ?? snapshot.actors[agentId]?.displayName ?? agentId;
|
|
59883
61254
|
}
|
|
59884
61255
|
function endpointForAgent(snapshot, agentId) {
|
|
59885
|
-
return Object.values(snapshot.endpoints).find((endpoint) => endpoint.agentId === agentId) ?? null;
|
|
61256
|
+
return Object.values(snapshot.endpoints).find((endpoint) => endpoint.agentId === agentId && !isInactiveEndpoint(snapshot, endpoint)) ?? null;
|
|
59886
61257
|
}
|
|
59887
61258
|
function buildMobileAgentSummary(snapshot, agent) {
|
|
59888
61259
|
const endpoint = endpointForAgent(snapshot, agent.id);
|
|
59889
61260
|
const flights = Object.values(snapshot.flights).filter((flight) => flight.targetAgentId === agent.id);
|
|
59890
61261
|
const hasWorkingFlight = flights.some((flight) => flight.state === "running");
|
|
59891
61262
|
const lastAuthoredMessageAt = Object.values(snapshot.messages).filter((message) => message.actorId === agent.id).reduce((latest, message) => {
|
|
59892
|
-
const createdAt =
|
|
61263
|
+
const createdAt = normalizeTimestampMs(message.createdAt);
|
|
59893
61264
|
return typeof createdAt === "number" && (!latest || createdAt > latest) ? createdAt : latest;
|
|
59894
61265
|
}, null);
|
|
59895
61266
|
const state = hasWorkingFlight ? "working" : endpoint && endpoint.state !== "offline" ? "available" : "offline";
|
|
@@ -59916,7 +61287,7 @@ function buildMobileSessionSummaries(snapshot) {
|
|
|
59916
61287
|
const latestMessage = messages2.at(-1) ?? null;
|
|
59917
61288
|
const directAgentId = conversation.kind === "direct" ? conversation.participantIds.find((participantId) => participantId !== "operator") ?? null : null;
|
|
59918
61289
|
const agent = directAgentId ? snapshot.agents[directAgentId] ?? null : null;
|
|
59919
|
-
if (!directAgentId || !agent || messages2.length === 0) {
|
|
61290
|
+
if (!directAgentId || !agent || isInactiveAgent(agent) || messages2.length === 0) {
|
|
59920
61291
|
return [];
|
|
59921
61292
|
}
|
|
59922
61293
|
const endpoint = endpointForAgent(snapshot, directAgentId);
|
|
@@ -59934,7 +61305,7 @@ function buildMobileSessionSummaries(snapshot) {
|
|
|
59934
61305
|
currentBranch: metadataString4(endpoint?.metadata, "branch") ?? metadataString4(endpoint?.metadata, "workspaceQualifier") ?? metadataString4(agent?.metadata, "branch") ?? metadataString4(agent?.metadata, "workspaceQualifier"),
|
|
59935
61306
|
preview: latestMessage?.body ?? null,
|
|
59936
61307
|
messageCount: messages2.length,
|
|
59937
|
-
lastMessageAt:
|
|
61308
|
+
lastMessageAt: normalizeTimestampMs(latestMessage?.createdAt),
|
|
59938
61309
|
workspaceRoot: endpoint?.projectRoot ?? endpoint?.cwd ?? null
|
|
59939
61310
|
}];
|
|
59940
61311
|
});
|
|
@@ -59958,7 +61329,7 @@ function buildMobileSessionSummaries(snapshot) {
|
|
|
59958
61329
|
return [...deduped.values()].sort((left, right) => (right.lastMessageAt ?? 0) - (left.lastMessageAt ?? 0));
|
|
59959
61330
|
}
|
|
59960
61331
|
function messagesForConversation(snapshot, conversationId) {
|
|
59961
|
-
return Object.values(snapshot.messages).filter((message) => message.conversationId === conversationId).sort((left, right) => (normalizeTimestamp2(left.createdAt) ?? 0) - (normalizeTimestamp2(right.createdAt) ?? 0));
|
|
61332
|
+
return Object.values(snapshot.messages).filter((message) => !isBrokerRequesterWaitTimeoutStatusMessage(message)).filter((message) => message.conversationId === conversationId).sort((left, right) => (normalizeTimestamp2(left.createdAt) ?? 0) - (normalizeTimestamp2(right.createdAt) ?? 0));
|
|
59962
61333
|
}
|
|
59963
61334
|
function pageMessagesForConversation(snapshot, conversationId, options = {}) {
|
|
59964
61335
|
const allMessages = messagesForConversation(snapshot, conversationId);
|
|
@@ -59995,7 +61366,7 @@ function pageMessagesForConversation(snapshot, conversationId, options = {}) {
|
|
|
59995
61366
|
function latestActiveFlightForAgent(snapshot, agentId) {
|
|
59996
61367
|
if (!agentId)
|
|
59997
61368
|
return null;
|
|
59998
|
-
return Object.values(snapshot.flights).filter((flight) => flight.targetAgentId === agentId &&
|
|
61369
|
+
return Object.values(snapshot.flights).filter((flight) => flight.targetAgentId === agentId && (flight.state === "running" || flight.state === "waiting") && !isRequesterWaitTimeoutFlight(flight)).sort((left, right) => (normalizeTimestamp2(right.startedAt) ?? 0) - (normalizeTimestamp2(left.startedAt) ?? 0))[0] ?? null;
|
|
59999
61370
|
}
|
|
60000
61371
|
async function loadMobileRelayState() {
|
|
60001
61372
|
const broker = await loadScoutBrokerContext();
|
|
@@ -60003,7 +61374,10 @@ async function loadMobileRelayState() {
|
|
|
60003
61374
|
return { agents: [], sessions: [] };
|
|
60004
61375
|
}
|
|
60005
61376
|
const snapshot = broker.snapshot;
|
|
60006
|
-
const agents = Object.values(snapshot.agents).
|
|
61377
|
+
const agents = Object.values(snapshot.agents).filter((agent) => !isInactiveAgent(agent)).filter((agent) => {
|
|
61378
|
+
const endpoints = Object.values(snapshot.endpoints).filter((endpoint) => endpoint.agentId === agent.id);
|
|
61379
|
+
return endpoints.length === 0 || endpoints.some((endpoint) => !isInactiveEndpoint(snapshot, endpoint));
|
|
61380
|
+
}).map((agent) => buildMobileAgentSummary(snapshot, agent)).sort((left, right) => (right.lastActiveAt ?? 0) - (left.lastActiveAt ?? 0) || left.title.localeCompare(right.title));
|
|
60007
61381
|
return {
|
|
60008
61382
|
agents,
|
|
60009
61383
|
sessions: buildMobileSessionSummaries(snapshot)
|
|
@@ -60110,10 +61484,10 @@ async function getScoutMobileSessionSnapshot(conversationId, options = {}, curre
|
|
|
60110
61484
|
const messages2 = messagePage.messages;
|
|
60111
61485
|
const activeFlight = latestActiveFlightForAgent(snapshot, directAgentId);
|
|
60112
61486
|
const lastAgentMessageAt = messages2.filter((message) => message.actorId === directAgentId).reduce((latest, message) => {
|
|
60113
|
-
const createdAt =
|
|
61487
|
+
const createdAt = normalizeTimestampMs(message.createdAt);
|
|
60114
61488
|
return typeof createdAt === "number" && (!latest || createdAt > latest) ? createdAt : latest;
|
|
60115
61489
|
}, null);
|
|
60116
|
-
const shouldShowWorkingTurn = Boolean(activeFlight && (
|
|
61490
|
+
const shouldShowWorkingTurn = Boolean(activeFlight && (normalizeTimestampMs(activeFlight.startedAt) ?? 0) > (lastAgentMessageAt ?? 0));
|
|
60117
61491
|
const turns = messages2.map((message) => ({
|
|
60118
61492
|
id: message.id,
|
|
60119
61493
|
status: "completed",
|
|
@@ -60187,7 +61561,7 @@ async function createScoutSession(input, currentDirectory, deviceId) {
|
|
|
60187
61561
|
throw new Error(`Invalid workspaceId.`);
|
|
60188
61562
|
}
|
|
60189
61563
|
const workspaceRoot = resolve16(rawWorkspaceId);
|
|
60190
|
-
const projectName =
|
|
61564
|
+
const projectName = basename13(workspaceRoot) || workspaceRoot;
|
|
60191
61565
|
const workspace = {
|
|
60192
61566
|
id: workspaceRoot,
|
|
60193
61567
|
title: projectName,
|
|
@@ -60264,6 +61638,9 @@ async function createScoutSession(input, currentDirectory, deviceId) {
|
|
|
60264
61638
|
};
|
|
60265
61639
|
}
|
|
60266
61640
|
async function sendScoutMobileMessage(input, currentDirectory, deviceId) {
|
|
61641
|
+
if (input.agentId === SCOUTBOT_AGENT_ID) {
|
|
61642
|
+
return sendScoutbotMobileThreadMessage(input, currentDirectory, deviceId);
|
|
61643
|
+
}
|
|
60267
61644
|
return sendScoutDirectMessage({
|
|
60268
61645
|
agentId: input.agentId,
|
|
60269
61646
|
body: input.body,
|
|
@@ -60276,6 +61653,88 @@ async function sendScoutMobileMessage(input, currentDirectory, deviceId) {
|
|
|
60276
61653
|
deviceId
|
|
60277
61654
|
});
|
|
60278
61655
|
}
|
|
61656
|
+
async function sendScoutbotMobileThreadMessage(input, currentDirectory, deviceId) {
|
|
61657
|
+
const broker = await loadScoutBrokerContext();
|
|
61658
|
+
if (!broker) {
|
|
61659
|
+
throw new Error("Scoutbot is not available.");
|
|
61660
|
+
}
|
|
61661
|
+
const conversationId = broker.snapshot.conversations[SCOUTBOT_LEGACY_CONVERSATION_ID] ? SCOUTBOT_LEGACY_CONVERSATION_ID : SCOUTBOT_DEFAULT_CONVERSATION_ID;
|
|
61662
|
+
const conversation = broker.snapshot.conversations[conversationId] ?? {
|
|
61663
|
+
id: conversationId,
|
|
61664
|
+
kind: "direct",
|
|
61665
|
+
title: conversationId === SCOUTBOT_LEGACY_CONVERSATION_ID ? "Scout" : "Scout \xB7 default",
|
|
61666
|
+
visibility: "private",
|
|
61667
|
+
shareMode: "local",
|
|
61668
|
+
authorityNodeId: broker.node.id,
|
|
61669
|
+
participantIds: ["operator", SCOUTBOT_AGENT_ID].sort(),
|
|
61670
|
+
metadata: {
|
|
61671
|
+
surface: "scoutbot",
|
|
61672
|
+
scoutbotThreadId: SCOUTBOT_DEFAULT_THREAD_ID
|
|
61673
|
+
}
|
|
61674
|
+
};
|
|
61675
|
+
if (!broker.snapshot.conversations[conversationId]) {
|
|
61676
|
+
await postMobileBrokerJson(broker.baseUrl, "/v1/conversations", conversation);
|
|
61677
|
+
}
|
|
61678
|
+
const now = Date.now();
|
|
61679
|
+
const messageId = createMobileBrokerEntityId("msg", now);
|
|
61680
|
+
const transportSessionId = scoutbotTransportSessionId(broker.snapshot);
|
|
61681
|
+
await postMobileBrokerJson(broker.baseUrl, "/v1/messages", {
|
|
61682
|
+
id: messageId,
|
|
61683
|
+
conversationId,
|
|
61684
|
+
actorId: "operator",
|
|
61685
|
+
originNodeId: broker.node.id,
|
|
61686
|
+
class: "agent",
|
|
61687
|
+
body: input.body.trim(),
|
|
61688
|
+
replyToMessageId: input.replyToMessageId ?? undefined,
|
|
61689
|
+
mentions: [{ actorId: SCOUTBOT_AGENT_ID, label: "@scoutbot" }],
|
|
61690
|
+
audience: { notify: [SCOUTBOT_AGENT_ID], reason: "direct_message" },
|
|
61691
|
+
visibility: "private",
|
|
61692
|
+
policy: "durable",
|
|
61693
|
+
createdAt: now,
|
|
61694
|
+
metadata: {
|
|
61695
|
+
source: "scout-mobile",
|
|
61696
|
+
destinationKind: "scoutbot_thread",
|
|
61697
|
+
destinationId: SCOUTBOT_DEFAULT_THREAD_ID,
|
|
61698
|
+
scoutbotThreadId: SCOUTBOT_DEFAULT_THREAD_ID,
|
|
61699
|
+
...transportSessionId ? { targetSessionId: transportSessionId } : {},
|
|
61700
|
+
referenceMessageIds: input.referenceMessageIds ?? [],
|
|
61701
|
+
clientMessageId: input.clientMessageId ?? null,
|
|
61702
|
+
...deviceId ? { deviceId } : {},
|
|
61703
|
+
relayMessageId: messageId,
|
|
61704
|
+
returnAddress: {
|
|
61705
|
+
actorId: "operator",
|
|
61706
|
+
conversationId,
|
|
61707
|
+
replyToMessageId: messageId,
|
|
61708
|
+
...transportSessionId ? { sessionId: transportSessionId } : {}
|
|
61709
|
+
}
|
|
61710
|
+
}
|
|
61711
|
+
});
|
|
61712
|
+
return {
|
|
61713
|
+
conversationId,
|
|
61714
|
+
messageId
|
|
61715
|
+
};
|
|
61716
|
+
}
|
|
61717
|
+
function scoutbotTransportSessionId(snapshot) {
|
|
61718
|
+
const endpoint = Object.values(snapshot.endpoints ?? {}).find((candidate) => candidate.agentId === SCOUTBOT_AGENT_ID && candidate.transport === "codex_app_server" && !isInactiveEndpoint(snapshot, candidate));
|
|
61719
|
+
if (!endpoint)
|
|
61720
|
+
return null;
|
|
61721
|
+
return metadataString4(endpoint.metadata, "threadId") ?? metadataString4(endpoint.metadata, "externalSessionId") ?? endpoint.sessionId?.trim() ?? null;
|
|
61722
|
+
}
|
|
61723
|
+
async function postMobileBrokerJson(baseUrl, path2, body) {
|
|
61724
|
+
const response = await fetch(new URL(path2, baseUrl), {
|
|
61725
|
+
method: "POST",
|
|
61726
|
+
headers: { "content-type": "application/json" },
|
|
61727
|
+
body: JSON.stringify(body)
|
|
61728
|
+
});
|
|
61729
|
+
if (!response.ok) {
|
|
61730
|
+
const text = await response.text().catch(() => "");
|
|
61731
|
+
throw new Error(`Broker ${path2} failed (${response.status}): ${text || response.statusText}`);
|
|
61732
|
+
}
|
|
61733
|
+
return await response.json();
|
|
61734
|
+
}
|
|
61735
|
+
function createMobileBrokerEntityId(prefix, createdAtMs) {
|
|
61736
|
+
return `${prefix}-${createdAtMs.toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
61737
|
+
}
|
|
60279
61738
|
async function deriveNewAgentName(projectName, branch, harness) {
|
|
60280
61739
|
const parts = [projectName.toLowerCase()];
|
|
60281
61740
|
if (branch) {
|
|
@@ -60342,7 +61801,7 @@ async function getScoutMobileActivity(filters = {}) {
|
|
|
60342
61801
|
limit: filters.limit ?? 100
|
|
60343
61802
|
});
|
|
60344
61803
|
}
|
|
60345
|
-
var DEFAULT_MOBILE_RECENT_TURN_LIMIT = 24, DEFAULT_MOBILE_HISTORY_PAGE_LIMIT = 40;
|
|
61804
|
+
var SCOUTBOT_AGENT_ID = "scoutbot", SCOUTBOT_DEFAULT_THREAD_ID = "thr-default", SCOUTBOT_DEFAULT_CONVERSATION_ID = "dm.operator.scoutbot.default", SCOUTBOT_LEGACY_CONVERSATION_ID = "dm.operator.scoutbot", DEFAULT_MOBILE_RECENT_TURN_LIMIT = 24, DEFAULT_MOBILE_HISTORY_PAGE_LIMIT = 40;
|
|
60346
61805
|
var init_service5 = __esm(() => {
|
|
60347
61806
|
init_harness_catalog();
|
|
60348
61807
|
init_setup();
|
|
@@ -60354,7 +61813,7 @@ var init_service5 = __esm(() => {
|
|
|
60354
61813
|
// ../../apps/desktop/src/core/pairing/runtime/bridge/server.ts
|
|
60355
61814
|
import { readdirSync as readdirSync4, readFileSync as readFileSync15, realpathSync, statSync as statSync5 } from "fs";
|
|
60356
61815
|
import { execSync as execSync2 } from "child_process";
|
|
60357
|
-
import { basename as
|
|
61816
|
+
import { basename as basename14, isAbsolute as isAbsolute3, join as join30, relative as relative3 } from "path";
|
|
60358
61817
|
import { homedir as homedir24 } from "os";
|
|
60359
61818
|
function replaySyncEvents(bridge, sessionId, lastSeq) {
|
|
60360
61819
|
return bridge.replay(sessionId, lastSeq);
|
|
@@ -60527,9 +61986,9 @@ async function handleRPCInner(bridge, req, deviceId) {
|
|
|
60527
61986
|
}
|
|
60528
61987
|
case "session/resume": {
|
|
60529
61988
|
const p = req.params;
|
|
60530
|
-
const sessionFilename =
|
|
61989
|
+
const sessionFilename = basename14(p.sessionPath, ".jsonl");
|
|
60531
61990
|
const parentDir = p.sessionPath.substring(0, p.sessionPath.lastIndexOf("/"));
|
|
60532
|
-
const dirName =
|
|
61991
|
+
const dirName = basename14(parentDir);
|
|
60533
61992
|
let cwd;
|
|
60534
61993
|
if (dirName.startsWith("-")) {
|
|
60535
61994
|
const candidate = "/" + dirName.slice(1).replace(/-/g, "/");
|
|
@@ -60596,7 +62055,7 @@ async function handleRPCInner(bridge, req, deviceId) {
|
|
|
60596
62055
|
return { id: req.id, error: { code: -32000, message: "Workspace target is not a directory" } };
|
|
60597
62056
|
}
|
|
60598
62057
|
const adapterType = p.adapter ?? "claude-code";
|
|
60599
|
-
const name = p.name ??
|
|
62058
|
+
const name = p.name ?? basename14(projectPath);
|
|
60600
62059
|
const session = await bridge.createSession(adapterType, {
|
|
60601
62060
|
name,
|
|
60602
62061
|
cwd: projectPath
|
|
@@ -62066,7 +63525,7 @@ function planMessageDeliveries(input) {
|
|
|
62066
63525
|
return [...deliveries2.values()];
|
|
62067
63526
|
}
|
|
62068
63527
|
|
|
62069
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
63528
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/entity.js
|
|
62070
63529
|
function is(value, type) {
|
|
62071
63530
|
if (!value || typeof value !== "object") {
|
|
62072
63531
|
return false;
|
|
@@ -62094,7 +63553,7 @@ var init_entity = __esm(() => {
|
|
|
62094
63553
|
hasOwnEntityKind = Symbol.for("drizzle:hasOwnEntityKind");
|
|
62095
63554
|
});
|
|
62096
63555
|
|
|
62097
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
63556
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/column.js
|
|
62098
63557
|
var Column;
|
|
62099
63558
|
var init_column = __esm(() => {
|
|
62100
63559
|
init_entity();
|
|
@@ -62148,7 +63607,7 @@ var init_column = __esm(() => {
|
|
|
62148
63607
|
};
|
|
62149
63608
|
});
|
|
62150
63609
|
|
|
62151
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
63610
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/column-builder.js
|
|
62152
63611
|
var ColumnBuilder;
|
|
62153
63612
|
var init_column_builder = __esm(() => {
|
|
62154
63613
|
init_entity();
|
|
@@ -62208,19 +63667,19 @@ var init_column_builder = __esm(() => {
|
|
|
62208
63667
|
};
|
|
62209
63668
|
});
|
|
62210
63669
|
|
|
62211
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
63670
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/table.utils.js
|
|
62212
63671
|
var TableName;
|
|
62213
63672
|
var init_table_utils = __esm(() => {
|
|
62214
63673
|
TableName = Symbol.for("drizzle:Name");
|
|
62215
63674
|
});
|
|
62216
63675
|
|
|
62217
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
63676
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/tracing-utils.js
|
|
62218
63677
|
function iife(fn, ...args) {
|
|
62219
63678
|
return fn(...args);
|
|
62220
63679
|
}
|
|
62221
63680
|
var init_tracing_utils = () => {};
|
|
62222
63681
|
|
|
62223
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
63682
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/pg-core/unique-constraint.js
|
|
62224
63683
|
function uniqueKeyName(table, columns) {
|
|
62225
63684
|
return `${table[TableName]}_${columns.join("_")}_unique`;
|
|
62226
63685
|
}
|
|
@@ -62228,7 +63687,7 @@ var init_unique_constraint = __esm(() => {
|
|
|
62228
63687
|
init_table_utils();
|
|
62229
63688
|
});
|
|
62230
63689
|
|
|
62231
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
63690
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/pg-core/columns/common.js
|
|
62232
63691
|
var PgColumn, ExtraConfigColumn;
|
|
62233
63692
|
var init_common = __esm(() => {
|
|
62234
63693
|
init_column();
|
|
@@ -62282,7 +63741,7 @@ var init_common = __esm(() => {
|
|
|
62282
63741
|
};
|
|
62283
63742
|
});
|
|
62284
63743
|
|
|
62285
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
63744
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/pg-core/columns/enum.js
|
|
62286
63745
|
function isPgEnum(obj) {
|
|
62287
63746
|
return !!obj && typeof obj === "function" && isPgEnumSym in obj && obj[isPgEnumSym] === true;
|
|
62288
63747
|
}
|
|
@@ -62317,7 +63776,7 @@ var init_enum = __esm(() => {
|
|
|
62317
63776
|
};
|
|
62318
63777
|
});
|
|
62319
63778
|
|
|
62320
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
63779
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/subquery.js
|
|
62321
63780
|
var Subquery;
|
|
62322
63781
|
var init_subquery = __esm(() => {
|
|
62323
63782
|
init_entity();
|
|
@@ -62336,11 +63795,11 @@ var init_subquery = __esm(() => {
|
|
|
62336
63795
|
};
|
|
62337
63796
|
});
|
|
62338
63797
|
|
|
62339
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
63798
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/version.js
|
|
62340
63799
|
var version2 = "0.45.2";
|
|
62341
63800
|
var init_version = () => {};
|
|
62342
63801
|
|
|
62343
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
63802
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/tracing.js
|
|
62344
63803
|
var otel, rawTracer, tracer;
|
|
62345
63804
|
var init_tracing = __esm(() => {
|
|
62346
63805
|
init_tracing_utils();
|
|
@@ -62370,13 +63829,13 @@ var init_tracing = __esm(() => {
|
|
|
62370
63829
|
};
|
|
62371
63830
|
});
|
|
62372
63831
|
|
|
62373
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
63832
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/view-common.js
|
|
62374
63833
|
var ViewBaseConfig;
|
|
62375
63834
|
var init_view_common = __esm(() => {
|
|
62376
63835
|
ViewBaseConfig = Symbol.for("drizzle:ViewBaseConfig");
|
|
62377
63836
|
});
|
|
62378
63837
|
|
|
62379
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
63838
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/table.js
|
|
62380
63839
|
var Schema, Columns, ExtraConfigColumns, OriginalName, BaseName, IsAlias, ExtraConfigBuilder, IsDrizzleTable, Table;
|
|
62381
63840
|
var init_table = __esm(() => {
|
|
62382
63841
|
init_entity();
|
|
@@ -62418,7 +63877,7 @@ var init_table = __esm(() => {
|
|
|
62418
63877
|
};
|
|
62419
63878
|
});
|
|
62420
63879
|
|
|
62421
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
63880
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sql/sql.js
|
|
62422
63881
|
function isSQLWrapper(value) {
|
|
62423
63882
|
return value !== null && value !== undefined && typeof value.getSQL === "function";
|
|
62424
63883
|
}
|
|
@@ -62782,7 +64241,7 @@ var init_sql = __esm(() => {
|
|
|
62782
64241
|
};
|
|
62783
64242
|
});
|
|
62784
64243
|
|
|
62785
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
64244
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/alias.js
|
|
62786
64245
|
var ColumnAliasProxyHandler, TableAliasProxyHandler;
|
|
62787
64246
|
var init_alias = __esm(() => {
|
|
62788
64247
|
init_column();
|
|
@@ -62844,13 +64303,13 @@ var init_alias = __esm(() => {
|
|
|
62844
64303
|
};
|
|
62845
64304
|
});
|
|
62846
64305
|
|
|
62847
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
64306
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/errors.js
|
|
62848
64307
|
var init_errors5 = () => {};
|
|
62849
64308
|
|
|
62850
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
64309
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/logger.js
|
|
62851
64310
|
var init_logger = () => {};
|
|
62852
64311
|
|
|
62853
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
64312
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/query-promise.js
|
|
62854
64313
|
var QueryPromise;
|
|
62855
64314
|
var init_query_promise = __esm(() => {
|
|
62856
64315
|
init_entity();
|
|
@@ -62875,7 +64334,7 @@ var init_query_promise = __esm(() => {
|
|
|
62875
64334
|
};
|
|
62876
64335
|
});
|
|
62877
64336
|
|
|
62878
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
64337
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/utils.js
|
|
62879
64338
|
function orderSelectedFields(fields, pathPrefix) {
|
|
62880
64339
|
return Object.entries(fields).reduce((result, [name, field]) => {
|
|
62881
64340
|
if (typeof name !== "string") {
|
|
@@ -62934,41 +64393,41 @@ var init_utils4 = __esm(() => {
|
|
|
62934
64393
|
textDecoder = typeof TextDecoder === "undefined" ? null : new TextDecoder;
|
|
62935
64394
|
});
|
|
62936
64395
|
|
|
62937
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
64396
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sql/expressions/conditions.js
|
|
62938
64397
|
var init_conditions = () => {};
|
|
62939
64398
|
|
|
62940
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
64399
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sql/expressions/select.js
|
|
62941
64400
|
var init_select = () => {};
|
|
62942
64401
|
|
|
62943
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
64402
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sql/expressions/index.js
|
|
62944
64403
|
var init_expressions = __esm(() => {
|
|
62945
64404
|
init_conditions();
|
|
62946
64405
|
init_select();
|
|
62947
64406
|
});
|
|
62948
64407
|
|
|
62949
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
64408
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/relations.js
|
|
62950
64409
|
var init_relations = () => {};
|
|
62951
64410
|
|
|
62952
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
64411
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sql/functions/aggregate.js
|
|
62953
64412
|
var init_aggregate = () => {};
|
|
62954
64413
|
|
|
62955
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
64414
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sql/functions/vector.js
|
|
62956
64415
|
var init_vector = () => {};
|
|
62957
64416
|
|
|
62958
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
64417
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sql/functions/index.js
|
|
62959
64418
|
var init_functions = __esm(() => {
|
|
62960
64419
|
init_aggregate();
|
|
62961
64420
|
init_vector();
|
|
62962
64421
|
});
|
|
62963
64422
|
|
|
62964
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
64423
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sql/index.js
|
|
62965
64424
|
var init_sql2 = __esm(() => {
|
|
62966
64425
|
init_expressions();
|
|
62967
64426
|
init_functions();
|
|
62968
64427
|
init_sql();
|
|
62969
64428
|
});
|
|
62970
64429
|
|
|
62971
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
64430
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/index.js
|
|
62972
64431
|
var init_drizzle_orm = __esm(() => {
|
|
62973
64432
|
init_alias();
|
|
62974
64433
|
init_column_builder();
|
|
@@ -62985,13 +64444,13 @@ var init_drizzle_orm = __esm(() => {
|
|
|
62985
64444
|
init_view_common();
|
|
62986
64445
|
});
|
|
62987
64446
|
|
|
62988
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
64447
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/alias.js
|
|
62989
64448
|
var init_alias2 = () => {};
|
|
62990
64449
|
|
|
62991
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
64450
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/checks.js
|
|
62992
64451
|
var init_checks4 = () => {};
|
|
62993
64452
|
|
|
62994
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
64453
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/foreign-keys.js
|
|
62995
64454
|
var ForeignKeyBuilder, ForeignKey;
|
|
62996
64455
|
var init_foreign_keys = __esm(() => {
|
|
62997
64456
|
init_entity();
|
|
@@ -63049,7 +64508,7 @@ var init_foreign_keys = __esm(() => {
|
|
|
63049
64508
|
};
|
|
63050
64509
|
});
|
|
63051
64510
|
|
|
63052
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
64511
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/unique-constraint.js
|
|
63053
64512
|
function uniqueKeyName2(table2, columns) {
|
|
63054
64513
|
return `${table2[TableName]}_${columns.join("_")}_unique`;
|
|
63055
64514
|
}
|
|
@@ -63057,7 +64516,7 @@ var init_unique_constraint2 = __esm(() => {
|
|
|
63057
64516
|
init_table_utils();
|
|
63058
64517
|
});
|
|
63059
64518
|
|
|
63060
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
64519
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/columns/common.js
|
|
63061
64520
|
var SQLiteColumnBuilder, SQLiteColumn;
|
|
63062
64521
|
var init_common2 = __esm(() => {
|
|
63063
64522
|
init_column_builder();
|
|
@@ -63115,7 +64574,7 @@ var init_common2 = __esm(() => {
|
|
|
63115
64574
|
};
|
|
63116
64575
|
});
|
|
63117
64576
|
|
|
63118
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
64577
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/columns/blob.js
|
|
63119
64578
|
function blob(a, b) {
|
|
63120
64579
|
const { name, config: config2 } = getColumnNameAndConfig(a, b);
|
|
63121
64580
|
if (config2?.mode === "json") {
|
|
@@ -63204,7 +64663,7 @@ var init_blob = __esm(() => {
|
|
|
63204
64663
|
};
|
|
63205
64664
|
});
|
|
63206
64665
|
|
|
63207
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
64666
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/columns/custom.js
|
|
63208
64667
|
function customType(customTypeParams) {
|
|
63209
64668
|
return (a, b) => {
|
|
63210
64669
|
const { name, config: config2 } = getColumnNameAndConfig(a, b);
|
|
@@ -63250,7 +64709,7 @@ var init_custom = __esm(() => {
|
|
|
63250
64709
|
};
|
|
63251
64710
|
});
|
|
63252
64711
|
|
|
63253
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
64712
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/columns/integer.js
|
|
63254
64713
|
function integer2(a, b) {
|
|
63255
64714
|
const { name, config: config2 } = getColumnNameAndConfig(a, b);
|
|
63256
64715
|
if (config2?.mode === "timestamp" || config2?.mode === "timestamp_ms") {
|
|
@@ -63352,7 +64811,7 @@ var init_integer = __esm(() => {
|
|
|
63352
64811
|
};
|
|
63353
64812
|
});
|
|
63354
64813
|
|
|
63355
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
64814
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/columns/numeric.js
|
|
63356
64815
|
function numeric(a, b) {
|
|
63357
64816
|
const { name, config: config2 } = getColumnNameAndConfig(a, b);
|
|
63358
64817
|
const mode = config2?.mode;
|
|
@@ -63423,7 +64882,7 @@ var init_numeric = __esm(() => {
|
|
|
63423
64882
|
};
|
|
63424
64883
|
});
|
|
63425
64884
|
|
|
63426
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
64885
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/columns/real.js
|
|
63427
64886
|
function real(name) {
|
|
63428
64887
|
return new SQLiteRealBuilder(name ?? "");
|
|
63429
64888
|
}
|
|
@@ -63448,7 +64907,7 @@ var init_real = __esm(() => {
|
|
|
63448
64907
|
};
|
|
63449
64908
|
});
|
|
63450
64909
|
|
|
63451
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
64910
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/columns/text.js
|
|
63452
64911
|
function text(a, b = {}) {
|
|
63453
64912
|
const { name, config: config2 } = getColumnNameAndConfig(a, b);
|
|
63454
64913
|
if (config2.mode === "json") {
|
|
@@ -63506,7 +64965,7 @@ var init_text = __esm(() => {
|
|
|
63506
64965
|
};
|
|
63507
64966
|
});
|
|
63508
64967
|
|
|
63509
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
64968
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/columns/index.js
|
|
63510
64969
|
var init_columns = __esm(() => {
|
|
63511
64970
|
init_blob();
|
|
63512
64971
|
init_common2();
|
|
@@ -63517,7 +64976,7 @@ var init_columns = __esm(() => {
|
|
|
63517
64976
|
init_text();
|
|
63518
64977
|
});
|
|
63519
64978
|
|
|
63520
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
64979
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/selection-proxy.js
|
|
63521
64980
|
var SelectionProxyHandler;
|
|
63522
64981
|
var init_selection_proxy = __esm(() => {
|
|
63523
64982
|
init_alias();
|
|
@@ -63578,7 +65037,7 @@ var init_selection_proxy = __esm(() => {
|
|
|
63578
65037
|
};
|
|
63579
65038
|
});
|
|
63580
65039
|
|
|
63581
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
65040
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/columns/all.js
|
|
63582
65041
|
function getSQLiteColumnBuilders() {
|
|
63583
65042
|
return {
|
|
63584
65043
|
blob,
|
|
@@ -63598,7 +65057,7 @@ var init_all = __esm(() => {
|
|
|
63598
65057
|
init_text();
|
|
63599
65058
|
});
|
|
63600
65059
|
|
|
63601
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
65060
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/table.js
|
|
63602
65061
|
function sqliteTableBase(name, columns, extraConfig, schema, baseName = name) {
|
|
63603
65062
|
const rawTable = new SQLiteTable(name, schema, baseName);
|
|
63604
65063
|
const parsedColumns = typeof columns === "function" ? columns(getSQLiteColumnBuilders()) : columns;
|
|
@@ -63636,7 +65095,7 @@ var init_table2 = __esm(() => {
|
|
|
63636
65095
|
};
|
|
63637
65096
|
});
|
|
63638
65097
|
|
|
63639
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
65098
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/indexes.js
|
|
63640
65099
|
function index(name) {
|
|
63641
65100
|
return new IndexBuilderOn(name, false);
|
|
63642
65101
|
}
|
|
@@ -63681,10 +65140,10 @@ var init_indexes = __esm(() => {
|
|
|
63681
65140
|
};
|
|
63682
65141
|
});
|
|
63683
65142
|
|
|
63684
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
65143
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/primary-keys.js
|
|
63685
65144
|
var init_primary_keys = () => {};
|
|
63686
65145
|
|
|
63687
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
65146
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/utils.js
|
|
63688
65147
|
function extractUsedTable(table2) {
|
|
63689
65148
|
if (is(table2, SQLiteTable)) {
|
|
63690
65149
|
return [`${table2[Table.Symbol.BaseName]}`];
|
|
@@ -63705,10 +65164,10 @@ var init_utils5 = __esm(() => {
|
|
|
63705
65164
|
init_table2();
|
|
63706
65165
|
});
|
|
63707
65166
|
|
|
63708
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
65167
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/query-builders/delete.js
|
|
63709
65168
|
var init_delete = () => {};
|
|
63710
65169
|
|
|
63711
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
65170
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/view-base.js
|
|
63712
65171
|
var SQLiteViewBase;
|
|
63713
65172
|
var init_view_base = __esm(() => {
|
|
63714
65173
|
init_entity();
|
|
@@ -63718,10 +65177,10 @@ var init_view_base = __esm(() => {
|
|
|
63718
65177
|
};
|
|
63719
65178
|
});
|
|
63720
65179
|
|
|
63721
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
65180
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/dialect.js
|
|
63722
65181
|
var init_dialect = () => {};
|
|
63723
65182
|
|
|
63724
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
65183
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/query-builders/query-builder.js
|
|
63725
65184
|
var TypedQueryBuilder;
|
|
63726
65185
|
var init_query_builder = __esm(() => {
|
|
63727
65186
|
init_entity();
|
|
@@ -63733,7 +65192,7 @@ var init_query_builder = __esm(() => {
|
|
|
63733
65192
|
};
|
|
63734
65193
|
});
|
|
63735
65194
|
|
|
63736
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
65195
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/query-builders/select.js
|
|
63737
65196
|
function createSetOperator(type, isAll) {
|
|
63738
65197
|
return (leftSelect, rightSelect, ...restSelects) => {
|
|
63739
65198
|
const setOperators = [rightSelect, ...restSelects].map((select2) => ({
|
|
@@ -64002,13 +65461,13 @@ var init_select2 = __esm(() => {
|
|
|
64002
65461
|
except = createSetOperator("except", false);
|
|
64003
65462
|
});
|
|
64004
65463
|
|
|
64005
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
65464
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/query-builders/query-builder.js
|
|
64006
65465
|
var init_query_builder2 = () => {};
|
|
64007
65466
|
|
|
64008
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
65467
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/query-builders/insert.js
|
|
64009
65468
|
var init_insert = () => {};
|
|
64010
65469
|
|
|
64011
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
65470
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/query-builders/update.js
|
|
64012
65471
|
var SQLiteUpdateBase;
|
|
64013
65472
|
var init_update = __esm(() => {
|
|
64014
65473
|
init_entity();
|
|
@@ -64112,7 +65571,7 @@ var init_update = __esm(() => {
|
|
|
64112
65571
|
};
|
|
64113
65572
|
});
|
|
64114
65573
|
|
|
64115
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
65574
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/query-builders/index.js
|
|
64116
65575
|
var init_query_builders = __esm(() => {
|
|
64117
65576
|
init_delete();
|
|
64118
65577
|
init_insert();
|
|
@@ -64121,16 +65580,16 @@ var init_query_builders = __esm(() => {
|
|
|
64121
65580
|
init_update();
|
|
64122
65581
|
});
|
|
64123
65582
|
|
|
64124
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
65583
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/db.js
|
|
64125
65584
|
var init_db = () => {};
|
|
64126
65585
|
|
|
64127
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
65586
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/session.js
|
|
64128
65587
|
var init_session = () => {};
|
|
64129
65588
|
|
|
64130
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
65589
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/view.js
|
|
64131
65590
|
var init_view = () => {};
|
|
64132
65591
|
|
|
64133
|
-
// ../../node_modules/.bun/drizzle-orm@0.45.2+
|
|
65592
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/index.js
|
|
64134
65593
|
var init_sqlite_core = __esm(() => {
|
|
64135
65594
|
init_alias2();
|
|
64136
65595
|
init_checks4();
|
|
@@ -64149,10 +65608,11 @@ var init_sqlite_core = __esm(() => {
|
|
|
64149
65608
|
});
|
|
64150
65609
|
|
|
64151
65610
|
// ../runtime/src/drizzle-schema.ts
|
|
64152
|
-
var deliveriesTable, deliveryAttemptsTable, briefingsTable;
|
|
65611
|
+
var epochMsNow, deliveriesTable, deliveryAttemptsTable, briefingsTable;
|
|
64153
65612
|
var init_drizzle_schema = __esm(() => {
|
|
64154
65613
|
init_drizzle_orm();
|
|
64155
65614
|
init_sqlite_core();
|
|
65615
|
+
epochMsNow = sql`(CAST(strftime('%s','now') AS INTEGER) * 1000)`;
|
|
64156
65616
|
deliveriesTable = sqliteTable("deliveries", {
|
|
64157
65617
|
id: text("id").primaryKey(),
|
|
64158
65618
|
messageId: text("message_id"),
|
|
@@ -64168,7 +65628,7 @@ var init_drizzle_schema = __esm(() => {
|
|
|
64168
65628
|
leaseOwner: text("lease_owner"),
|
|
64169
65629
|
leaseExpiresAt: integer2("lease_expires_at"),
|
|
64170
65630
|
metadataJson: text("metadata_json"),
|
|
64171
|
-
createdAt: integer2("created_at").notNull().default(
|
|
65631
|
+
createdAt: integer2("created_at").notNull().default(epochMsNow)
|
|
64172
65632
|
}, (table3) => [
|
|
64173
65633
|
index("idx_deliveries_status_transport").on(table3.status, table3.transport)
|
|
64174
65634
|
]);
|
|
@@ -64195,7 +65655,7 @@ var init_drizzle_schema = __esm(() => {
|
|
|
64195
65655
|
snapshotJson: text("snapshot_json").notNull(),
|
|
64196
65656
|
callJson: text("call_json").notNull(),
|
|
64197
65657
|
markdown: text("markdown"),
|
|
64198
|
-
createdAt: integer2("created_at").notNull().default(
|
|
65658
|
+
createdAt: integer2("created_at").notNull().default(epochMsNow)
|
|
64199
65659
|
}, (table3) => [
|
|
64200
65660
|
index("idx_briefings_created_at").on(table3.createdAt),
|
|
64201
65661
|
index("idx_briefings_kind_created_at").on(table3.kind, table3.createdAt)
|
|
@@ -64936,6 +66396,17 @@ var init_mesh_forwarding = __esm(() => {
|
|
|
64936
66396
|
init_src();
|
|
64937
66397
|
init_iroh_bridge();
|
|
64938
66398
|
});
|
|
66399
|
+
|
|
66400
|
+
// ../runtime/src/invocation-lifecycle-read-model.ts
|
|
66401
|
+
var init_invocation_lifecycle_read_model = __esm(() => {
|
|
66402
|
+
init_src();
|
|
66403
|
+
});
|
|
66404
|
+
|
|
66405
|
+
// ../runtime/src/broker-core-service.ts
|
|
66406
|
+
var init_broker_core_service = __esm(() => {
|
|
66407
|
+
init_invocation_lifecycle_read_model();
|
|
66408
|
+
});
|
|
66409
|
+
|
|
64939
66410
|
// ../runtime/src/scout-broker.ts
|
|
64940
66411
|
var init_scout_broker = __esm(() => {
|
|
64941
66412
|
init_src();
|
|
@@ -66310,10 +67781,34 @@ function buildScoutVantagePlan(input) {
|
|
|
66310
67781
|
manifest: {
|
|
66311
67782
|
kind: HUDSON_VANTAGE_SETUP_KIND,
|
|
66312
67783
|
schemaVersion: HUDSON_VANTAGE_SCHEMA_VERSION,
|
|
67784
|
+
workspaceID: workspaceIdFor(input.currentDirectory),
|
|
66313
67785
|
source: "openscout",
|
|
66314
67786
|
generatedAt,
|
|
66315
67787
|
currentDirectory: input.currentDirectory,
|
|
66316
67788
|
broker: buildBrokerSummary(input.broker?.baseUrl ?? null, brokerNode, brokerSnapshot),
|
|
67789
|
+
presentation: {
|
|
67790
|
+
title: "Scout Vantage",
|
|
67791
|
+
subtitle: "local runtime handoff",
|
|
67792
|
+
badge: "runtime",
|
|
67793
|
+
cobrand: "OpenScout",
|
|
67794
|
+
productName: "Scout",
|
|
67795
|
+
hostName: "Hudson Vantage",
|
|
67796
|
+
theme: "jade",
|
|
67797
|
+
accent: "cyan"
|
|
67798
|
+
},
|
|
67799
|
+
style: {
|
|
67800
|
+
preset: "jade",
|
|
67801
|
+
canvasGridMode: "dots",
|
|
67802
|
+
canvasGridStep: 18,
|
|
67803
|
+
focusPadding: 12
|
|
67804
|
+
},
|
|
67805
|
+
viewport: { fit: true },
|
|
67806
|
+
layout: {
|
|
67807
|
+
canvasTool: "select",
|
|
67808
|
+
navigationFilter: "all",
|
|
67809
|
+
minimapCollapsed: false,
|
|
67810
|
+
inspectorCollapsed: false
|
|
67811
|
+
},
|
|
66317
67812
|
focus: focusAgentId ? { agentId: focusAgentId } : focusNativeSessionId ? { nativeSessionId: focusNativeSessionId } : null,
|
|
66318
67813
|
selectedAgentIds,
|
|
66319
67814
|
selectedNativeSessionIds,
|
|
@@ -66520,6 +68015,10 @@ function tmuxTargetKey(target) {
|
|
|
66520
68015
|
function stableNodeId(kind, value) {
|
|
66521
68016
|
return `vantage.${kind}.${slugify2(value)}.${fnv1a(value)}`;
|
|
66522
68017
|
}
|
|
68018
|
+
function workspaceIdFor(currentDirectory) {
|
|
68019
|
+
const lastSegment = currentDirectory.split(/[\\/]+/g).filter(Boolean).at(-1) ?? "workspace";
|
|
68020
|
+
return `openscout-${slugify2(lastSegment)}`;
|
|
68021
|
+
}
|
|
66523
68022
|
function slugify2(value) {
|
|
66524
68023
|
const slug = value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
|
|
66525
68024
|
return slug || "node";
|
|
@@ -66571,6 +68070,7 @@ var init_src3 = __esm(() => {
|
|
|
66571
68070
|
init_tailscale();
|
|
66572
68071
|
init_broker_process_manager();
|
|
66573
68072
|
init_broker_api();
|
|
68073
|
+
init_broker_core_service();
|
|
66574
68074
|
init_local_agents();
|
|
66575
68075
|
init_control_plane_agents();
|
|
66576
68076
|
init_scout_broker();
|
|
@@ -69874,7 +71374,7 @@ var init_tail_fanout = __esm(() => {
|
|
|
69874
71374
|
// ../../apps/desktop/src/core/pairing/runtime/bridge/router.ts
|
|
69875
71375
|
import { readFileSync as readFileSync17, readdirSync as readdirSync5, realpathSync as realpathSync2, statSync as statSync6 } from "fs";
|
|
69876
71376
|
import { execSync as execSync3 } from "child_process";
|
|
69877
|
-
import { basename as
|
|
71377
|
+
import { basename as basename15, isAbsolute as isAbsolute4, join as join32, relative as relative4 } from "path";
|
|
69878
71378
|
import { homedir as homedir25 } from "os";
|
|
69879
71379
|
function resolveMobileCurrentDirectory2() {
|
|
69880
71380
|
const config2 = resolveConfig();
|
|
@@ -70351,9 +71851,9 @@ var init_router = __esm(() => {
|
|
|
70351
71851
|
adapterType: exports_external.string().optional(),
|
|
70352
71852
|
name: exports_external.string().optional()
|
|
70353
71853
|
})).mutation(async ({ input, ctx }) => {
|
|
70354
|
-
const sessionFilename =
|
|
71854
|
+
const sessionFilename = basename15(input.sessionPath, ".jsonl");
|
|
70355
71855
|
const parentDir = input.sessionPath.substring(0, input.sessionPath.lastIndexOf("/"));
|
|
70356
|
-
const dirName =
|
|
71856
|
+
const dirName = basename15(parentDir);
|
|
70357
71857
|
let cwd;
|
|
70358
71858
|
if (dirName.startsWith("-")) {
|
|
70359
71859
|
const candidate = "/" + dirName.slice(1).replace(/-/g, "/");
|
|
@@ -70653,7 +72153,7 @@ var init_router = __esm(() => {
|
|
|
70653
72153
|
});
|
|
70654
72154
|
}
|
|
70655
72155
|
const adapterType = input.adapter ?? "claude-code";
|
|
70656
|
-
const name = input.name ??
|
|
72156
|
+
const name = input.name ?? basename15(projectPath);
|
|
70657
72157
|
return ctx.bridge.createSession(adapterType, {
|
|
70658
72158
|
name,
|
|
70659
72159
|
cwd: projectPath
|
|
@@ -75005,6 +76505,7 @@ function renderServerCommandHelp() {
|
|
|
75005
76505
|
"",
|
|
75006
76506
|
"Usage:",
|
|
75007
76507
|
" scout server start [options]",
|
|
76508
|
+
" scout server restart [options]",
|
|
75008
76509
|
" scout server open [options]",
|
|
75009
76510
|
" scout server caddyfile [options]",
|
|
75010
76511
|
" scout server edge [options]",
|
|
@@ -75013,6 +76514,7 @@ function renderServerCommandHelp() {
|
|
|
75013
76514
|
"",
|
|
75014
76515
|
"Subcommands:",
|
|
75015
76516
|
" start Start the Scout web UI server.",
|
|
76517
|
+
" restart Restart the Scout web UI server via the broker supervisor.",
|
|
75016
76518
|
" open Open the Scout web UI (starts server on demand if needed).",
|
|
75017
76519
|
" caddyfile Print the local edge Caddyfile for scout.local.",
|
|
75018
76520
|
" edge Publish local names and run the Caddy edge.",
|
|
@@ -75264,6 +76766,14 @@ function parseServerSelection(args) {
|
|
|
75264
76766
|
mode: "openscout-web"
|
|
75265
76767
|
};
|
|
75266
76768
|
}
|
|
76769
|
+
if (args[0] === "restart") {
|
|
76770
|
+
return {
|
|
76771
|
+
action: "restart",
|
|
76772
|
+
flagArgs: args.slice(1),
|
|
76773
|
+
entry: resolveScoutControlPlaneWebServerEntry(),
|
|
76774
|
+
mode: "openscout-web"
|
|
76775
|
+
};
|
|
76776
|
+
}
|
|
75267
76777
|
if (args[0] === "open") {
|
|
75268
76778
|
return {
|
|
75269
76779
|
action: "open",
|
|
@@ -75673,6 +77183,11 @@ async function runServerCommand(context, args) {
|
|
|
75673
77183
|
context.output.writeText(renderLocalEdgeTrustResult(ensureScoutLocalEdgeTrust({ env: mergedEnv })));
|
|
75674
77184
|
return;
|
|
75675
77185
|
}
|
|
77186
|
+
if (selection.action === "restart") {
|
|
77187
|
+
const result = await restartScoutWebServer();
|
|
77188
|
+
context.output.writeValue(result, renderServerRestartResult);
|
|
77189
|
+
return;
|
|
77190
|
+
}
|
|
75676
77191
|
const bunExecutable = resolveBunExecutable4(mergedEnv);
|
|
75677
77192
|
await new Promise((resolvePromise, rejectPromise) => {
|
|
75678
77193
|
const child = spawn5(bunExecutable, ["run", selection.entry], {
|
|
@@ -75703,6 +77218,69 @@ async function runServerCommand(context, args) {
|
|
|
75703
77218
|
});
|
|
75704
77219
|
});
|
|
75705
77220
|
}
|
|
77221
|
+
async function fetchSupervisorStatus() {
|
|
77222
|
+
const brokerUrl = resolveScoutBrokerUrl();
|
|
77223
|
+
const response = await fetch(new URL("/v1/web/status", brokerUrl));
|
|
77224
|
+
if (!response.ok) {
|
|
77225
|
+
throw new ScoutCliError(`broker supervisor returned HTTP ${response.status}`);
|
|
77226
|
+
}
|
|
77227
|
+
return await response.json();
|
|
77228
|
+
}
|
|
77229
|
+
async function waitForSupervisor(predicate, timeoutMs, intervalMs = 150) {
|
|
77230
|
+
const deadline = Date.now() + timeoutMs;
|
|
77231
|
+
let last = null;
|
|
77232
|
+
while (Date.now() < deadline) {
|
|
77233
|
+
last = await fetchSupervisorStatus().catch(() => last);
|
|
77234
|
+
if (last && predicate(last))
|
|
77235
|
+
return last;
|
|
77236
|
+
await new Promise((r) => setTimeout(r, intervalMs));
|
|
77237
|
+
}
|
|
77238
|
+
if (!last) {
|
|
77239
|
+
throw new ScoutCliError("broker supervisor did not respond within the timeout");
|
|
77240
|
+
}
|
|
77241
|
+
return last;
|
|
77242
|
+
}
|
|
77243
|
+
async function restartScoutWebServer() {
|
|
77244
|
+
const started = Date.now();
|
|
77245
|
+
const before = await fetchSupervisorStatus().catch(() => null);
|
|
77246
|
+
if (!before || !before.pid) {
|
|
77247
|
+
throw new ScoutCliError("Scout web server is not running under the broker supervisor \u2014 start it with `scout server start`.");
|
|
77248
|
+
}
|
|
77249
|
+
const previousPid = before.pid;
|
|
77250
|
+
try {
|
|
77251
|
+
process.kill(previousPid, "SIGTERM");
|
|
77252
|
+
} catch (error48) {
|
|
77253
|
+
const code = error48.code;
|
|
77254
|
+
if (code === "EPERM") {
|
|
77255
|
+
throw new ScoutCliError(`not permitted to signal pid ${previousPid}`);
|
|
77256
|
+
}
|
|
77257
|
+
if (code === "ESRCH") {} else {
|
|
77258
|
+
throw error48;
|
|
77259
|
+
}
|
|
77260
|
+
}
|
|
77261
|
+
const drained = await waitForSupervisor((status) => status.pid === null || status.pid !== previousPid, 12000);
|
|
77262
|
+
const drainMs = Date.now() - started;
|
|
77263
|
+
const respawned = drained.pid && drained.pid !== previousPid ? drained : await waitForSupervisor((status) => status.running && status.pid !== null && status.pid !== previousPid, 15000);
|
|
77264
|
+
return {
|
|
77265
|
+
webUrl: respawned.webUrl,
|
|
77266
|
+
port: respawned.port,
|
|
77267
|
+
previousPid,
|
|
77268
|
+
newPid: respawned.pid,
|
|
77269
|
+
drainMs,
|
|
77270
|
+
totalMs: Date.now() - started
|
|
77271
|
+
};
|
|
77272
|
+
}
|
|
77273
|
+
function renderServerRestartResult(value) {
|
|
77274
|
+
return [
|
|
77275
|
+
`Restarted Scout web server`,
|
|
77276
|
+
` Previous PID: ${value.previousPid}`,
|
|
77277
|
+
` New PID: ${value.newPid ?? "(unknown)"}`,
|
|
77278
|
+
` URL: ${value.webUrl ?? "(unknown)"}`,
|
|
77279
|
+
` Drain: ${value.drainMs}ms`,
|
|
77280
|
+
` Total: ${value.totalMs}ms`
|
|
77281
|
+
].join(`
|
|
77282
|
+
`);
|
|
77283
|
+
}
|
|
75706
77284
|
var SERVER_OPEN_TIMEOUT_MS = 15000, SERVER_HEALTH_TIMEOUT_MS = 1500;
|
|
75707
77285
|
var init_server4 = __esm(() => {
|
|
75708
77286
|
init_local_config();
|
|
@@ -75710,6 +77288,7 @@ var init_server4 = __esm(() => {
|
|
|
75710
77288
|
init_tool_resolution();
|
|
75711
77289
|
init_setup();
|
|
75712
77290
|
init_local_edge_dependencies();
|
|
77291
|
+
init_service();
|
|
75713
77292
|
init_errors();
|
|
75714
77293
|
});
|
|
75715
77294
|
|
|
@@ -75832,7 +77411,7 @@ import { resolve as resolve18, dirname as dirname17 } from "path";
|
|
|
75832
77411
|
import { fileURLToPath as fileURLToPath11 } from "url";
|
|
75833
77412
|
import { resolve as resolve22, isAbsolute as isAbsolute5, parse as parse7 } from "path";
|
|
75834
77413
|
import { existsSync as existsSync25 } from "fs";
|
|
75835
|
-
import { basename as
|
|
77414
|
+
import { basename as basename16, join as join35 } from "path";
|
|
75836
77415
|
import os from "os";
|
|
75837
77416
|
import path2 from "path";
|
|
75838
77417
|
import { EventEmitter as EventEmitter3 } from "events";
|
|
@@ -79123,7 +80702,7 @@ function getBunfsRootPath() {
|
|
|
79123
80702
|
return process.platform === "win32" ? "B:\\~BUN\\root" : "/$bunfs/root";
|
|
79124
80703
|
}
|
|
79125
80704
|
function normalizeBunfsPath(fileName) {
|
|
79126
|
-
return join35(getBunfsRootPath(),
|
|
80705
|
+
return join35(getBunfsRootPath(), basename16(fileName));
|
|
79127
80706
|
}
|
|
79128
80707
|
function addDefaultParsers(parsers) {
|
|
79129
80708
|
for (const parser of parsers) {
|
|
@@ -136307,14 +137886,18 @@ function displayName(actorId) {
|
|
|
136307
137886
|
return segments[0] || trimmed;
|
|
136308
137887
|
}
|
|
136309
137888
|
function formatClock(value) {
|
|
136310
|
-
const
|
|
137889
|
+
const timestamp = normalizeUnixTimestamp2(value);
|
|
137890
|
+
if (timestamp === null)
|
|
137891
|
+
return "--:--:--";
|
|
137892
|
+
const date6 = new Date(timestamp * 1000);
|
|
136311
137893
|
return [date6.getHours(), date6.getMinutes(), date6.getSeconds()].map((entry) => String(entry).padStart(2, "0")).join(":");
|
|
136312
137894
|
}
|
|
136313
137895
|
function formatRelative(value) {
|
|
136314
|
-
|
|
137896
|
+
const timestamp = normalizeUnixTimestamp2(value);
|
|
137897
|
+
if (timestamp === null) {
|
|
136315
137898
|
return "not seen";
|
|
136316
137899
|
}
|
|
136317
|
-
const age = Math.max(0, Math.floor(Date.now() / 1000) -
|
|
137900
|
+
const age = Math.max(0, Math.floor(Date.now() / 1000) - timestamp);
|
|
136318
137901
|
if (age < 60)
|
|
136319
137902
|
return `${age}s ago`;
|
|
136320
137903
|
if (age < 3600)
|
|
@@ -136324,7 +137907,10 @@ function formatRelative(value) {
|
|
|
136324
137907
|
return `${Math.floor(age / 86400)}d ago`;
|
|
136325
137908
|
}
|
|
136326
137909
|
function formatUptime2(value) {
|
|
136327
|
-
const
|
|
137910
|
+
const timestamp = normalizeUnixTimestamp2(value);
|
|
137911
|
+
if (timestamp === null)
|
|
137912
|
+
return "unknown";
|
|
137913
|
+
const age = Math.max(0, Math.floor(Date.now() / 1000) - timestamp);
|
|
136328
137914
|
if (age < 60)
|
|
136329
137915
|
return `${age}s`;
|
|
136330
137916
|
if (age < 3600)
|
|
@@ -136495,15 +138081,15 @@ function ChatPanel({
|
|
|
136495
138081
|
}) {
|
|
136496
138082
|
const bodyWidth = Math.max(24, width - 20);
|
|
136497
138083
|
const ordered = snapshot.recentMessages.slice().sort((left, right) => {
|
|
136498
|
-
const leftTs = left.createdAt;
|
|
136499
|
-
const rightTs = right.createdAt;
|
|
138084
|
+
const leftTs = normalizeUnixTimestamp2(left.createdAt) ?? 0;
|
|
138085
|
+
const rightTs = normalizeUnixTimestamp2(right.createdAt) ?? 0;
|
|
136500
138086
|
if (leftTs !== rightTs)
|
|
136501
138087
|
return leftTs - rightTs;
|
|
136502
138088
|
return String(left.id).localeCompare(String(right.id));
|
|
136503
138089
|
});
|
|
136504
138090
|
const rendered = ordered.flatMap((message) => {
|
|
136505
138091
|
const actor = truncate(displayName(message.actorId), 12).padEnd(12, " ");
|
|
136506
|
-
const stamp = formatClock(
|
|
138092
|
+
const stamp = formatClock(message.createdAt);
|
|
136507
138093
|
const lines = wrapText(message.body, bodyWidth);
|
|
136508
138094
|
const color = messageTone(message);
|
|
136509
138095
|
return lines.map((line, index2) => ({
|
|
@@ -137890,7 +139476,7 @@ var SCOUT_COMMANDS = [
|
|
|
137890
139476
|
{ name: "restart", summary: "Restart configured local agents" },
|
|
137891
139477
|
{ name: "menu", summary: "Launch the OpenScout macOS menu bar app" },
|
|
137892
139478
|
{ name: "vantage", summary: "Build a Hudson Vantage terminal canvas plan" },
|
|
137893
|
-
{ name: "config", summary: "View or set user config (name, etc.)" },
|
|
139479
|
+
{ name: "config", summary: "View or set user config (name, handle, etc.)" },
|
|
137894
139480
|
{ name: "mesh", summary: "Mesh status and diagnostics" },
|
|
137895
139481
|
{ name: "pair", summary: "Pair a companion device via QR" },
|
|
137896
139482
|
{ name: "server", summary: "Run the Scout web UI (Bun; see: scout server start/open)" },
|
|
@@ -137930,6 +139516,7 @@ function renderScoutHelp(version3 = "0.2.19") {
|
|
|
137930
139516
|
"Fast path:",
|
|
137931
139517
|
' scout send --to hudson "ready for review" # tell / update in a DM',
|
|
137932
139518
|
' scout ask --to hudson "review the parser" # owned work; wait for ack',
|
|
139519
|
+
' scout ask --project ../talkie "compare auth" # no agent id needed; route by project path',
|
|
137933
139520
|
" scout ask --to hudson --prompt-file ./handoff.md",
|
|
137934
139521
|
" scout wait inv_123 --timeout 600 # follow an existing ask",
|
|
137935
139522
|
" scout label watch release:0.2.66 --interval 2 # label-scoped activity firehose",
|
|
@@ -137972,6 +139559,12 @@ function renderScoutHelp(version3 = "0.2.19") {
|
|
|
137972
139559
|
' scout ask --as premotion.master.mini --to hudson "build the editor"',
|
|
137973
139560
|
" scout ask --to hudson --prompt-file ./handoff.md",
|
|
137974
139561
|
"",
|
|
139562
|
+
"Project targets:",
|
|
139563
|
+
' scout ask --project ../talkie "compare auth" # broker resolves the concrete agent/session',
|
|
139564
|
+
' scout ask --project ../talkie --harness codex "review this from Codex"',
|
|
139565
|
+
" scout ask '>> project:../talkie compare auth' # composer route form; quote >> in shells",
|
|
139566
|
+
" use --project when you know the repo path but not the current Scout handle",
|
|
139567
|
+
"",
|
|
137975
139568
|
"Routing:",
|
|
137976
139569
|
' scout send --to hudson "ready for review" # one target -> DM',
|
|
137977
139570
|
' scout send --channel triage "need two reviewers" # explicit group thread',
|