@ganglion/xacpx 0.9.2 → 0.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js
CHANGED
|
@@ -851,7 +851,6 @@ var init_cli_update = __esm(() => {
|
|
|
851
851
|
updateFailed: (name, error) => `${name} update failed: ${error}`,
|
|
852
852
|
targetNotFound: (name) => `Update target not found: ${name}`,
|
|
853
853
|
targetVersionUnknown: (name) => `${name}: cannot check latest version; skipped.`,
|
|
854
|
-
targetNotPinned: (name) => `${name} has no recorded version; use \`xacpx plugin update ${name}\` or specify a version explicitly.`,
|
|
855
854
|
multiTargetNonInteractive: "Installed plugins detected; in non-interactive mode use `xacpx update --all` or `xacpx update <name>`.",
|
|
856
855
|
selectionPrompt: "Select items to update (numbers, comma-separated; a=all; Enter to cancel): ",
|
|
857
856
|
selectionInvalid: (part) => `Invalid selection: ${part}`,
|
|
@@ -1922,7 +1921,6 @@ var init_cli_update2 = __esm(() => {
|
|
|
1922
1921
|
updateFailed: (name, error) => `${name} 更新失败:${error}`,
|
|
1923
1922
|
targetNotFound: (name) => `没有找到更新项:${name}`,
|
|
1924
1923
|
targetVersionUnknown: (name) => `${name} 无法检查最新版本,已跳过。`,
|
|
1925
|
-
targetNotPinned: (name) => `${name} 未记录当前版本;请先使用 \`xacpx plugin update ${name}\` 或显式选择版本。`,
|
|
1926
1924
|
multiTargetNonInteractive: "检测到已安装插件;非交互模式请使用 `xacpx update --all` 或 `xacpx update <name>`。",
|
|
1927
1925
|
selectionPrompt: "请选择要更新的项目(数字,逗号分隔,a=全部,回车取消):",
|
|
1928
1926
|
selectionInvalid: (part) => `无效选择:${part}`,
|
|
@@ -11959,6 +11957,41 @@ var init_version = __esm(() => {
|
|
|
11959
11957
|
XACPX_CORE_VERSION = readVersion();
|
|
11960
11958
|
});
|
|
11961
11959
|
|
|
11960
|
+
// src/orchestration/endpoint-probe.ts
|
|
11961
|
+
import { createConnection } from "node:net";
|
|
11962
|
+
async function canConnectToEndpoint(path3, timeoutMs) {
|
|
11963
|
+
return await new Promise((resolve) => {
|
|
11964
|
+
const socket = createConnection(path3);
|
|
11965
|
+
let settled = false;
|
|
11966
|
+
let timer;
|
|
11967
|
+
const finish = (result) => {
|
|
11968
|
+
if (settled) {
|
|
11969
|
+
return;
|
|
11970
|
+
}
|
|
11971
|
+
settled = true;
|
|
11972
|
+
if (timer) {
|
|
11973
|
+
clearTimeout(timer);
|
|
11974
|
+
}
|
|
11975
|
+
socket.destroy();
|
|
11976
|
+
resolve(result);
|
|
11977
|
+
};
|
|
11978
|
+
if (timeoutMs !== undefined && timeoutMs > 0) {
|
|
11979
|
+
timer = setTimeout(() => finish(true), timeoutMs);
|
|
11980
|
+
timer.unref?.();
|
|
11981
|
+
}
|
|
11982
|
+
socket.once("connect", () => finish(true));
|
|
11983
|
+
socket.once("error", (error2) => {
|
|
11984
|
+
const code = error2.code;
|
|
11985
|
+
if (code === "ENOENT" || code === "ECONNREFUSED") {
|
|
11986
|
+
finish(false);
|
|
11987
|
+
return;
|
|
11988
|
+
}
|
|
11989
|
+
finish(true);
|
|
11990
|
+
});
|
|
11991
|
+
});
|
|
11992
|
+
}
|
|
11993
|
+
var init_endpoint_probe = () => {};
|
|
11994
|
+
|
|
11962
11995
|
// src/orchestration/task-watch-timeouts.ts
|
|
11963
11996
|
var DEFAULT_TASK_WATCH_TIMEOUT_MS = 60000, MAX_TASK_WATCH_TIMEOUT_MS, DEFAULT_TASK_WATCH_POLL_INTERVAL_MS = 1000, MAX_TASK_WATCH_POLL_INTERVAL_MS = 1e4, TASK_WATCH_RPC_TIMEOUT_PADDING_MS = 5000;
|
|
11964
11997
|
var init_task_watch_timeouts = __esm(() => {
|
|
@@ -12014,6 +12047,14 @@ function escapeRegExp(s) {
|
|
|
12014
12047
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
12015
12048
|
}
|
|
12016
12049
|
|
|
12050
|
+
// src/orchestration/coordinator-identity.ts
|
|
12051
|
+
function stableCoordinatorSession(transportSession) {
|
|
12052
|
+
return transportSession.replace(/:reset-\d+$/, "");
|
|
12053
|
+
}
|
|
12054
|
+
function sameCoordinatorSession(a, b) {
|
|
12055
|
+
return stableCoordinatorSession(a) === stableCoordinatorSession(b);
|
|
12056
|
+
}
|
|
12057
|
+
|
|
12017
12058
|
// src/util/text.ts
|
|
12018
12059
|
function truncateText(text, maxLength, ellipsis = "…") {
|
|
12019
12060
|
if (text.length <= maxLength)
|
|
@@ -21516,7 +21557,7 @@ async function promptWithSession(context, session3, chatKey, text, reply, replyC
|
|
|
21516
21557
|
if (context.orchestration) {
|
|
21517
21558
|
try {
|
|
21518
21559
|
await context.orchestration.recordCoordinatorRouteContext?.({
|
|
21519
|
-
coordinatorSession: session3.transportSession,
|
|
21560
|
+
coordinatorSession: stableCoordinatorSession(session3.transportSession),
|
|
21520
21561
|
chatKey,
|
|
21521
21562
|
sessionAlias: session3.alias,
|
|
21522
21563
|
...replyContextToken ? { replyContextToken } : {},
|
|
@@ -21599,7 +21640,7 @@ async function preparePromptWithFallback(context, session3, chatKey, text, reply
|
|
|
21599
21640
|
try {
|
|
21600
21641
|
return await buildCoordinatorPrompt({
|
|
21601
21642
|
orchestration: orchestration3,
|
|
21602
|
-
coordinatorSession: session3.transportSession,
|
|
21643
|
+
coordinatorSession: stableCoordinatorSession(session3.transportSession),
|
|
21603
21644
|
chatKey,
|
|
21604
21645
|
userText: text,
|
|
21605
21646
|
...replyContextToken ? { replyContextToken } : {},
|
|
@@ -21934,6 +21975,7 @@ async function handleDelegateRequest(context, chatKey, targetAgent, task, role,
|
|
|
21934
21975
|
if (!session3) {
|
|
21935
21976
|
return { text: t().orchestration.noCurrentSession };
|
|
21936
21977
|
}
|
|
21978
|
+
const coordinatorSession = stableCoordinatorSession(session3.transportSession);
|
|
21937
21979
|
const orchestration3 = getOrchestration(context);
|
|
21938
21980
|
if (!orchestration3) {
|
|
21939
21981
|
return { text: renderOrchestrationUnavailable() };
|
|
@@ -21941,7 +21983,7 @@ async function handleDelegateRequest(context, chatKey, targetAgent, task, role,
|
|
|
21941
21983
|
const result = await orchestration3.requestDelegate({
|
|
21942
21984
|
sourceHandle: session3.transportSession,
|
|
21943
21985
|
sourceKind: "coordinator",
|
|
21944
|
-
coordinatorSession
|
|
21986
|
+
coordinatorSession,
|
|
21945
21987
|
workspace: session3.workspace,
|
|
21946
21988
|
targetAgent,
|
|
21947
21989
|
task,
|
|
@@ -21958,12 +22000,13 @@ async function handleGroupCreate(context, chatKey, title) {
|
|
|
21958
22000
|
if (!session3) {
|
|
21959
22001
|
return { text: t().orchestration.noCurrentSession };
|
|
21960
22002
|
}
|
|
22003
|
+
const coordinatorSession = stableCoordinatorSession(session3.transportSession);
|
|
21961
22004
|
const orchestration3 = getOrchestration(context);
|
|
21962
22005
|
if (!orchestration3) {
|
|
21963
22006
|
return { text: renderOrchestrationUnavailable() };
|
|
21964
22007
|
}
|
|
21965
22008
|
const group = await orchestration3.createGroup({
|
|
21966
|
-
coordinatorSession
|
|
22009
|
+
coordinatorSession,
|
|
21967
22010
|
title
|
|
21968
22011
|
});
|
|
21969
22012
|
return { text: renderGroupCreated(group) };
|
|
@@ -21973,12 +22016,13 @@ async function handleGroupList(context, chatKey, filter) {
|
|
|
21973
22016
|
if (!session3) {
|
|
21974
22017
|
return { text: t().orchestration.noCurrentSession };
|
|
21975
22018
|
}
|
|
22019
|
+
const coordinatorSession = stableCoordinatorSession(session3.transportSession);
|
|
21976
22020
|
const orchestration3 = getOrchestration(context);
|
|
21977
22021
|
if (!orchestration3) {
|
|
21978
22022
|
return { text: renderOrchestrationUnavailable() };
|
|
21979
22023
|
}
|
|
21980
22024
|
const groups = await orchestration3.listGroupSummaries({
|
|
21981
|
-
coordinatorSession
|
|
22025
|
+
coordinatorSession,
|
|
21982
22026
|
...filter ?? {}
|
|
21983
22027
|
});
|
|
21984
22028
|
return { text: renderGroupList(groups) };
|
|
@@ -21988,13 +22032,14 @@ async function handleGroupGet(context, chatKey, groupId) {
|
|
|
21988
22032
|
if (!session3) {
|
|
21989
22033
|
return { text: t().orchestration.noCurrentSession };
|
|
21990
22034
|
}
|
|
22035
|
+
const coordinatorSession = stableCoordinatorSession(session3.transportSession);
|
|
21991
22036
|
const orchestration3 = getOrchestration(context);
|
|
21992
22037
|
if (!orchestration3) {
|
|
21993
22038
|
return { text: renderOrchestrationUnavailable() };
|
|
21994
22039
|
}
|
|
21995
22040
|
const group = await orchestration3.getGroupSummary({
|
|
21996
22041
|
groupId,
|
|
21997
|
-
coordinatorSession
|
|
22042
|
+
coordinatorSession
|
|
21998
22043
|
});
|
|
21999
22044
|
if (!group) {
|
|
22000
22045
|
return { text: t().orchestration.groupNotFound };
|
|
@@ -22006,20 +22051,21 @@ async function handleGroupCancel(context, chatKey, groupId) {
|
|
|
22006
22051
|
if (!session3) {
|
|
22007
22052
|
return { text: t().orchestration.noCurrentSession };
|
|
22008
22053
|
}
|
|
22054
|
+
const coordinatorSession = stableCoordinatorSession(session3.transportSession);
|
|
22009
22055
|
const orchestration3 = getOrchestration(context);
|
|
22010
22056
|
if (!orchestration3) {
|
|
22011
22057
|
return { text: renderOrchestrationUnavailable() };
|
|
22012
22058
|
}
|
|
22013
22059
|
const group = await orchestration3.getGroupSummary({
|
|
22014
22060
|
groupId,
|
|
22015
|
-
coordinatorSession
|
|
22061
|
+
coordinatorSession
|
|
22016
22062
|
});
|
|
22017
22063
|
if (!group) {
|
|
22018
22064
|
return { text: t().orchestration.groupNotFound };
|
|
22019
22065
|
}
|
|
22020
22066
|
const cancelled = await orchestration3.cancelGroup({
|
|
22021
22067
|
groupId,
|
|
22022
|
-
coordinatorSession
|
|
22068
|
+
coordinatorSession
|
|
22023
22069
|
});
|
|
22024
22070
|
return { text: renderGroupCancelSuccess(cancelled) };
|
|
22025
22071
|
}
|
|
@@ -22028,13 +22074,14 @@ async function handleGroupDelegate(context, chatKey, groupId, targetAgent, task,
|
|
|
22028
22074
|
if (!session3) {
|
|
22029
22075
|
return { text: t().orchestration.noCurrentSession };
|
|
22030
22076
|
}
|
|
22077
|
+
const coordinatorSession = stableCoordinatorSession(session3.transportSession);
|
|
22031
22078
|
const orchestration3 = getOrchestration(context);
|
|
22032
22079
|
if (!orchestration3) {
|
|
22033
22080
|
return { text: renderOrchestrationUnavailable() };
|
|
22034
22081
|
}
|
|
22035
22082
|
const group = await orchestration3.getGroupSummary({
|
|
22036
22083
|
groupId,
|
|
22037
|
-
coordinatorSession
|
|
22084
|
+
coordinatorSession
|
|
22038
22085
|
});
|
|
22039
22086
|
if (!group) {
|
|
22040
22087
|
return { text: t().orchestration.groupNotFound };
|
|
@@ -22046,12 +22093,13 @@ async function handleTaskList(context, chatKey, filter) {
|
|
|
22046
22093
|
if (!session3) {
|
|
22047
22094
|
return { text: t().orchestration.noCurrentSession };
|
|
22048
22095
|
}
|
|
22096
|
+
const coordinatorSession = stableCoordinatorSession(session3.transportSession);
|
|
22049
22097
|
const orchestration3 = getOrchestration(context);
|
|
22050
22098
|
if (!orchestration3) {
|
|
22051
22099
|
return { text: renderOrchestrationUnavailable() };
|
|
22052
22100
|
}
|
|
22053
22101
|
const tasks = await orchestration3.listTasks({
|
|
22054
|
-
coordinatorSession
|
|
22102
|
+
coordinatorSession,
|
|
22055
22103
|
...filter ?? {}
|
|
22056
22104
|
});
|
|
22057
22105
|
return { text: renderTaskList2(tasks) };
|
|
@@ -22061,12 +22109,13 @@ async function handleTaskGet(context, chatKey, taskId) {
|
|
|
22061
22109
|
if (!session3) {
|
|
22062
22110
|
return { text: t().orchestration.noCurrentSession };
|
|
22063
22111
|
}
|
|
22112
|
+
const coordinatorSession = stableCoordinatorSession(session3.transportSession);
|
|
22064
22113
|
const orchestration3 = getOrchestration(context);
|
|
22065
22114
|
if (!orchestration3) {
|
|
22066
22115
|
return { text: renderOrchestrationUnavailable() };
|
|
22067
22116
|
}
|
|
22068
22117
|
const task = await orchestration3.getTask(taskId);
|
|
22069
|
-
if (!task || task.coordinatorSession
|
|
22118
|
+
if (!task || !sameCoordinatorSession(task.coordinatorSession, coordinatorSession)) {
|
|
22070
22119
|
return { text: t().orchestration.taskNotFound };
|
|
22071
22120
|
}
|
|
22072
22121
|
return { text: renderTaskSummary2(task) };
|
|
@@ -22076,12 +22125,13 @@ async function handleTaskApprove(context, chatKey, taskId) {
|
|
|
22076
22125
|
if (!session3) {
|
|
22077
22126
|
return { text: t().orchestration.noCurrentSession };
|
|
22078
22127
|
}
|
|
22128
|
+
const coordinatorSession = stableCoordinatorSession(session3.transportSession);
|
|
22079
22129
|
const orchestration3 = getOrchestration(context);
|
|
22080
22130
|
if (!orchestration3) {
|
|
22081
22131
|
return { text: renderOrchestrationUnavailable() };
|
|
22082
22132
|
}
|
|
22083
22133
|
const task = await orchestration3.getTask(taskId);
|
|
22084
|
-
if (!task || task.coordinatorSession
|
|
22134
|
+
if (!task || !sameCoordinatorSession(task.coordinatorSession, coordinatorSession)) {
|
|
22085
22135
|
return { text: t().orchestration.taskNotFound };
|
|
22086
22136
|
}
|
|
22087
22137
|
if (task.status !== "needs_confirmation") {
|
|
@@ -22089,7 +22139,7 @@ async function handleTaskApprove(context, chatKey, taskId) {
|
|
|
22089
22139
|
}
|
|
22090
22140
|
const approved = await orchestration3.approveTask({
|
|
22091
22141
|
taskId,
|
|
22092
|
-
coordinatorSession
|
|
22142
|
+
coordinatorSession
|
|
22093
22143
|
});
|
|
22094
22144
|
return { text: renderTaskApprovalSuccess2(approved) };
|
|
22095
22145
|
}
|
|
@@ -22098,12 +22148,13 @@ async function handleTaskReject(context, chatKey, taskId) {
|
|
|
22098
22148
|
if (!session3) {
|
|
22099
22149
|
return { text: t().orchestration.noCurrentSession };
|
|
22100
22150
|
}
|
|
22151
|
+
const coordinatorSession = stableCoordinatorSession(session3.transportSession);
|
|
22101
22152
|
const orchestration3 = getOrchestration(context);
|
|
22102
22153
|
if (!orchestration3) {
|
|
22103
22154
|
return { text: renderOrchestrationUnavailable() };
|
|
22104
22155
|
}
|
|
22105
22156
|
const task = await orchestration3.getTask(taskId);
|
|
22106
|
-
if (!task || task.coordinatorSession
|
|
22157
|
+
if (!task || !sameCoordinatorSession(task.coordinatorSession, coordinatorSession)) {
|
|
22107
22158
|
return { text: t().orchestration.taskNotFound };
|
|
22108
22159
|
}
|
|
22109
22160
|
if (task.status !== "needs_confirmation") {
|
|
@@ -22111,7 +22162,7 @@ async function handleTaskReject(context, chatKey, taskId) {
|
|
|
22111
22162
|
}
|
|
22112
22163
|
const rejected = await orchestration3.cancelTask({
|
|
22113
22164
|
taskId,
|
|
22114
|
-
coordinatorSession
|
|
22165
|
+
coordinatorSession
|
|
22115
22166
|
});
|
|
22116
22167
|
return { text: renderTaskRejectSuccess(rejected) };
|
|
22117
22168
|
}
|
|
@@ -22120,17 +22171,18 @@ async function handleTaskCancel(context, chatKey, taskId) {
|
|
|
22120
22171
|
if (!session3) {
|
|
22121
22172
|
return { text: t().orchestration.noCurrentSession };
|
|
22122
22173
|
}
|
|
22174
|
+
const coordinatorSession = stableCoordinatorSession(session3.transportSession);
|
|
22123
22175
|
const orchestration3 = getOrchestration(context);
|
|
22124
22176
|
if (!orchestration3) {
|
|
22125
22177
|
return { text: renderOrchestrationUnavailable() };
|
|
22126
22178
|
}
|
|
22127
22179
|
const task = await orchestration3.getTask(taskId);
|
|
22128
|
-
if (!task || task.coordinatorSession
|
|
22180
|
+
if (!task || !sameCoordinatorSession(task.coordinatorSession, coordinatorSession)) {
|
|
22129
22181
|
return { text: t().orchestration.taskNotFound };
|
|
22130
22182
|
}
|
|
22131
22183
|
const cancelled = await orchestration3.requestTaskCancellation({
|
|
22132
22184
|
taskId,
|
|
22133
|
-
coordinatorSession
|
|
22185
|
+
coordinatorSession
|
|
22134
22186
|
});
|
|
22135
22187
|
return { text: renderTaskCancelSuccess(cancelled) };
|
|
22136
22188
|
}
|
|
@@ -22139,11 +22191,12 @@ async function handleTasksClean(context, chatKey) {
|
|
|
22139
22191
|
if (!session3) {
|
|
22140
22192
|
return { text: t().orchestration.noCurrentSession };
|
|
22141
22193
|
}
|
|
22194
|
+
const coordinatorSession = stableCoordinatorSession(session3.transportSession);
|
|
22142
22195
|
const orchestration3 = getOrchestration(context);
|
|
22143
22196
|
if (!orchestration3) {
|
|
22144
22197
|
return { text: renderOrchestrationUnavailable() };
|
|
22145
22198
|
}
|
|
22146
|
-
const result = await orchestration3.cleanTasks(
|
|
22199
|
+
const result = await orchestration3.cleanTasks(coordinatorSession);
|
|
22147
22200
|
return { text: renderTasksCleanResult(result.removedTasks, result.removedBindings) };
|
|
22148
22201
|
}
|
|
22149
22202
|
async function getCurrentSession(context, chatKey) {
|
|
@@ -24204,7 +24257,7 @@ class CommandRouter {
|
|
|
24204
24257
|
return await this.measureTransportCall("has_session", session3, () => this.transport.hasSession(session3));
|
|
24205
24258
|
}
|
|
24206
24259
|
async promptTransportSession(session3, text, reply, replyContext, media, abortSignal, onToolEvent, onThought, perfSpan) {
|
|
24207
|
-
session3.mcpCoordinatorSession ??= session3.transportSession;
|
|
24260
|
+
session3.mcpCoordinatorSession ??= stableCoordinatorSession(session3.transportSession);
|
|
24208
24261
|
let done = false;
|
|
24209
24262
|
let abortRequested = false;
|
|
24210
24263
|
let cancelOnAbort;
|
|
@@ -24455,7 +24508,7 @@ var init_console_agent = __esm(() => {
|
|
|
24455
24508
|
|
|
24456
24509
|
// src/orchestration/orchestration-server.ts
|
|
24457
24510
|
import { rm as rm8 } from "node:fs/promises";
|
|
24458
|
-
import {
|
|
24511
|
+
import { createServer } from "node:net";
|
|
24459
24512
|
|
|
24460
24513
|
class OrchestrationServer {
|
|
24461
24514
|
endpoint;
|
|
@@ -24683,7 +24736,7 @@ class OrchestrationServer {
|
|
|
24683
24736
|
if (!task) {
|
|
24684
24737
|
return null;
|
|
24685
24738
|
}
|
|
24686
|
-
if (task.coordinatorSession
|
|
24739
|
+
if (!sameCoordinatorSession(task.coordinatorSession, coordinatorSession)) {
|
|
24687
24740
|
return null;
|
|
24688
24741
|
}
|
|
24689
24742
|
return task;
|
|
@@ -24948,29 +25001,6 @@ function requireTaskQuestions(params, key) {
|
|
|
24948
25001
|
};
|
|
24949
25002
|
});
|
|
24950
25003
|
}
|
|
24951
|
-
async function canConnectToEndpoint(path14) {
|
|
24952
|
-
return await new Promise((resolve3) => {
|
|
24953
|
-
const socket = createConnection2(path14);
|
|
24954
|
-
let settled = false;
|
|
24955
|
-
const finish = (result) => {
|
|
24956
|
-
if (settled) {
|
|
24957
|
-
return;
|
|
24958
|
-
}
|
|
24959
|
-
settled = true;
|
|
24960
|
-
socket.destroy();
|
|
24961
|
-
resolve3(result);
|
|
24962
|
-
};
|
|
24963
|
-
socket.once("connect", () => finish(true));
|
|
24964
|
-
socket.once("error", (error2) => {
|
|
24965
|
-
const code = error2.code;
|
|
24966
|
-
if (code === "ENOENT" || code === "ECONNREFUSED") {
|
|
24967
|
-
finish(false);
|
|
24968
|
-
return;
|
|
24969
|
-
}
|
|
24970
|
-
finish(true);
|
|
24971
|
-
});
|
|
24972
|
-
});
|
|
24973
|
-
}
|
|
24974
25004
|
async function listen(server, path14) {
|
|
24975
25005
|
await new Promise((resolve3, reject) => {
|
|
24976
25006
|
const onError = (error2) => {
|
|
@@ -24993,6 +25023,7 @@ var OrchestrationInvalidRequestError, ORCHESTRATION_RPC_METHODS;
|
|
|
24993
25023
|
var init_orchestration_server = __esm(() => {
|
|
24994
25024
|
init_orchestration_ipc();
|
|
24995
25025
|
init_task_watch_timeouts();
|
|
25026
|
+
init_endpoint_probe();
|
|
24996
25027
|
OrchestrationInvalidRequestError = class OrchestrationInvalidRequestError extends Error {
|
|
24997
25028
|
};
|
|
24998
25029
|
ORCHESTRATION_RPC_METHODS = new Set([
|
|
@@ -25193,7 +25224,7 @@ class OrchestrationService {
|
|
|
25193
25224
|
async getGroupSummary(input) {
|
|
25194
25225
|
const state = await this.deps.loadState();
|
|
25195
25226
|
const group = this.ensureGroups(state)[input.groupId];
|
|
25196
|
-
if (!group || group.coordinatorSession
|
|
25227
|
+
if (!group || !sameCoordinatorSession(group.coordinatorSession, input.coordinatorSession)) {
|
|
25197
25228
|
return null;
|
|
25198
25229
|
}
|
|
25199
25230
|
return this.buildGroupSummary(group, Object.values(state.orchestration.tasks).filter((task) => task.groupId === input.groupId));
|
|
@@ -25205,7 +25236,7 @@ class OrchestrationService {
|
|
|
25205
25236
|
const now = this.deps.now().getTime();
|
|
25206
25237
|
const sortField = input.sort ?? "updatedAt";
|
|
25207
25238
|
const order = input.order ?? "desc";
|
|
25208
|
-
return Object.values(this.ensureGroups(state)).filter((group) => group.coordinatorSession
|
|
25239
|
+
return Object.values(this.ensureGroups(state)).filter((group) => sameCoordinatorSession(group.coordinatorSession, input.coordinatorSession)).map((group) => ({
|
|
25209
25240
|
group,
|
|
25210
25241
|
summary: this.buildGroupSummary(group, tasks.filter((task) => task.groupId === group.groupId))
|
|
25211
25242
|
})).filter(({ summary }) => {
|
|
@@ -25695,7 +25726,7 @@ class OrchestrationService {
|
|
|
25695
25726
|
const workerSession = task.workerSession;
|
|
25696
25727
|
const taskStillOwnsWorkerSession = current?.workerSession === workerSession;
|
|
25697
25728
|
const currentBinding = state.orchestration.workerBindings[workerSession];
|
|
25698
|
-
const bindingStillBelongsToThisStartup = currentBinding?.sourceHandle === workerSession && currentBinding.coordinatorSession
|
|
25729
|
+
const bindingStillBelongsToThisStartup = currentBinding?.sourceHandle === workerSession && sameCoordinatorSession(currentBinding.coordinatorSession, task.coordinatorSession) && currentBinding.workspace === task.workspace && currentBinding.cwd === task.cwd && currentBinding.targetAgent === task.targetAgent && currentBinding.role === task.role;
|
|
25699
25730
|
const otherActiveOwner = Object.values(state.orchestration.tasks).some((candidate) => candidate.taskId !== task.taskId && candidate.workerSession === workerSession && (!this.isTerminalStatus(candidate.status) || candidate.reviewPending !== undefined));
|
|
25700
25731
|
const restoreOrDeleteBinding = () => {
|
|
25701
25732
|
if (!bindingStillBelongsToThisStartup || otherActiveOwner) {
|
|
@@ -25754,7 +25785,7 @@ class OrchestrationService {
|
|
|
25754
25785
|
current.updatedAt = now;
|
|
25755
25786
|
this.bumpGroupUpdated(state, current.groupId, now);
|
|
25756
25787
|
const currentBinding = state.orchestration.workerBindings[workerSession];
|
|
25757
|
-
const bindingStillBelongsToThisStartup = currentBinding?.sourceHandle === workerSession && currentBinding.coordinatorSession
|
|
25788
|
+
const bindingStillBelongsToThisStartup = currentBinding?.sourceHandle === workerSession && sameCoordinatorSession(currentBinding.coordinatorSession, task.coordinatorSession) && currentBinding.workspace === task.workspace && currentBinding.cwd === task.cwd && currentBinding.targetAgent === task.targetAgent && currentBinding.role === task.role;
|
|
25758
25789
|
const otherActiveOwner = Object.values(state.orchestration.tasks).some((candidate) => candidate.taskId !== task.taskId && candidate.workerSession === workerSession && (!this.isTerminalStatus(candidate.status) || candidate.reviewPending !== undefined));
|
|
25759
25790
|
if (bindingStillBelongsToThisStartup && !otherActiveOwner) {
|
|
25760
25791
|
if (input.previousBinding) {
|
|
@@ -25773,7 +25804,7 @@ class OrchestrationService {
|
|
|
25773
25804
|
const state = await this.deps.loadState();
|
|
25774
25805
|
const workerSession = task.workerSession;
|
|
25775
25806
|
const currentBinding = state.orchestration.workerBindings[workerSession];
|
|
25776
|
-
const bindingStillBelongsToThisStartup = currentBinding?.sourceHandle === workerSession && currentBinding.coordinatorSession
|
|
25807
|
+
const bindingStillBelongsToThisStartup = currentBinding?.sourceHandle === workerSession && sameCoordinatorSession(currentBinding.coordinatorSession, task.coordinatorSession) && currentBinding.workspace === task.workspace && currentBinding.cwd === task.cwd && currentBinding.targetAgent === task.targetAgent && currentBinding.role === task.role;
|
|
25777
25808
|
if (!bindingStillBelongsToThisStartup) {
|
|
25778
25809
|
return false;
|
|
25779
25810
|
}
|
|
@@ -25946,7 +25977,7 @@ class OrchestrationService {
|
|
|
25946
25977
|
while (true) {
|
|
25947
25978
|
const state = await this.deps.loadState();
|
|
25948
25979
|
const task = state.orchestration.tasks[input.taskId];
|
|
25949
|
-
if (!task || task.coordinatorSession
|
|
25980
|
+
if (!task || !sameCoordinatorSession(task.coordinatorSession, input.coordinatorSession)) {
|
|
25950
25981
|
return { status: "not_found", task: null, events: [], nextAfterSeq: afterSeq };
|
|
25951
25982
|
}
|
|
25952
25983
|
const snapshot = { ...task };
|
|
@@ -26004,7 +26035,8 @@ class OrchestrationService {
|
|
|
26004
26035
|
return await this.mutate(async () => {
|
|
26005
26036
|
const state = await this.deps.loadState();
|
|
26006
26037
|
const now = this.deps.now().toISOString();
|
|
26007
|
-
const
|
|
26038
|
+
const routeKey = stableCoordinatorSession(input.coordinatorSession);
|
|
26039
|
+
const existing = this.ensureCoordinatorRoutes(state)[routeKey];
|
|
26008
26040
|
const sameChat = existing?.chatKey === input.chatKey;
|
|
26009
26041
|
const hasAccountId = input.accountId !== undefined;
|
|
26010
26042
|
const hasReplyContextToken = input.replyContextToken !== undefined;
|
|
@@ -26018,14 +26050,14 @@ class OrchestrationService {
|
|
|
26018
26050
|
replyContextToken: existing.replyContextToken
|
|
26019
26051
|
} : undefined;
|
|
26020
26052
|
const route = {
|
|
26021
|
-
coordinatorSession:
|
|
26053
|
+
coordinatorSession: routeKey,
|
|
26022
26054
|
chatKey: input.chatKey,
|
|
26023
26055
|
...input.sessionAlias ? { sessionAlias: input.sessionAlias } : {},
|
|
26024
26056
|
...replyRoute ? replyRoute : {},
|
|
26025
26057
|
...buildCoordinatorRouteChatMetadata(input, sameChat ? existing : undefined),
|
|
26026
26058
|
updatedAt: now
|
|
26027
26059
|
};
|
|
26028
|
-
this.ensureCoordinatorRoutes(state)[
|
|
26060
|
+
this.ensureCoordinatorRoutes(state)[routeKey] = route;
|
|
26029
26061
|
await this.deps.saveState(state);
|
|
26030
26062
|
return { ...route };
|
|
26031
26063
|
});
|
|
@@ -26269,7 +26301,7 @@ class OrchestrationService {
|
|
|
26269
26301
|
return task;
|
|
26270
26302
|
});
|
|
26271
26303
|
const now = this.deps.now().toISOString();
|
|
26272
|
-
const route = this.snapshotCoordinatorDeliveryRoute(this.ensureCoordinatorRoutes(state)[input.coordinatorSession]);
|
|
26304
|
+
const route = this.snapshotCoordinatorDeliveryRoute(this.ensureCoordinatorRoutes(state)[stableCoordinatorSession(input.coordinatorSession)]);
|
|
26273
26305
|
if (coordinatorState.activePackageId) {
|
|
26274
26306
|
const activePackage = this.ensureHumanQuestionPackages(state)[coordinatorState.activePackageId];
|
|
26275
26307
|
if (!activePackage) {
|
|
@@ -26371,7 +26403,7 @@ class OrchestrationService {
|
|
|
26371
26403
|
if (!packageRecord) {
|
|
26372
26404
|
throw new Error(`package "${input.packageId}" does not exist`);
|
|
26373
26405
|
}
|
|
26374
|
-
if (packageRecord.coordinatorSession
|
|
26406
|
+
if (!sameCoordinatorSession(packageRecord.coordinatorSession, input.coordinatorSession)) {
|
|
26375
26407
|
throw new Error(`package "${input.packageId}" belongs to coordinator "${packageRecord.coordinatorSession}", not "${input.coordinatorSession}"`);
|
|
26376
26408
|
}
|
|
26377
26409
|
if (packageRecord.status !== "active") {
|
|
@@ -26386,7 +26418,7 @@ class OrchestrationService {
|
|
|
26386
26418
|
}
|
|
26387
26419
|
let route = this.resolveFrozenPackageMessageRoute(message);
|
|
26388
26420
|
if (!route) {
|
|
26389
|
-
route = this.snapshotCoordinatorDeliveryRoute(this.ensureCoordinatorRoutes(state)[input.coordinatorSession]) ?? null;
|
|
26421
|
+
route = this.snapshotCoordinatorDeliveryRoute(this.ensureCoordinatorRoutes(state)[stableCoordinatorSession(input.coordinatorSession)]) ?? null;
|
|
26390
26422
|
if (route) {
|
|
26391
26423
|
Object.assign(message, this.serializeFrozenDeliveryRoute(route));
|
|
26392
26424
|
}
|
|
@@ -26455,7 +26487,7 @@ class OrchestrationService {
|
|
|
26455
26487
|
if (this.isExternalCoordinatorSession(state, coordinatorSession)) {
|
|
26456
26488
|
return null;
|
|
26457
26489
|
}
|
|
26458
|
-
const coordinatorState = state.orchestration.coordinatorQuestionState[coordinatorSession];
|
|
26490
|
+
const coordinatorState = state.orchestration.coordinatorQuestionState[stableCoordinatorSession(coordinatorSession)];
|
|
26459
26491
|
const activePackageId = coordinatorState?.activePackageId;
|
|
26460
26492
|
if (!activePackageId) {
|
|
26461
26493
|
return null;
|
|
@@ -26595,7 +26627,7 @@ class OrchestrationService {
|
|
|
26595
26627
|
const bindings = state.orchestration.workerBindings;
|
|
26596
26628
|
const terminalTaskIds = [];
|
|
26597
26629
|
for (const [taskId, task] of Object.entries(tasks)) {
|
|
26598
|
-
if (task.coordinatorSession
|
|
26630
|
+
if (sameCoordinatorSession(task.coordinatorSession, coordinatorSession) && this.isTerminalStatus(task.status) && task.reviewPending === undefined) {
|
|
26599
26631
|
terminalTaskIds.push(taskId);
|
|
26600
26632
|
}
|
|
26601
26633
|
}
|
|
@@ -26605,7 +26637,7 @@ class OrchestrationService {
|
|
|
26605
26637
|
const remainingWorkerSessions = new Set(Object.values(tasks).map((task) => task.workerSession).filter(Boolean));
|
|
26606
26638
|
let removedBindings = 0;
|
|
26607
26639
|
for (const [workerSession, binding] of Object.entries(bindings)) {
|
|
26608
|
-
if (binding.coordinatorSession
|
|
26640
|
+
if (!sameCoordinatorSession(binding.coordinatorSession, coordinatorSession)) {
|
|
26609
26641
|
continue;
|
|
26610
26642
|
}
|
|
26611
26643
|
if (!remainingWorkerSessions.has(workerSession)) {
|
|
@@ -26625,16 +26657,17 @@ class OrchestrationService {
|
|
|
26625
26657
|
}
|
|
26626
26658
|
async listSessionBlockingTasks(transportSession) {
|
|
26627
26659
|
const state = await this.deps.loadState();
|
|
26628
|
-
return Object.values(state.orchestration.tasks).filter((task) => (!this.isTerminalStatus(task.status) || task.reviewPending !== undefined) && (task.coordinatorSession
|
|
26660
|
+
return Object.values(state.orchestration.tasks).filter((task) => (!this.isTerminalStatus(task.status) || task.reviewPending !== undefined) && (sameCoordinatorSession(task.coordinatorSession, transportSession) || task.workerSession !== undefined && sameCoordinatorSession(task.workerSession, transportSession))).map((task) => ({ ...task }));
|
|
26629
26661
|
}
|
|
26630
26662
|
async purgeSessionReferences(transportSession) {
|
|
26631
26663
|
return await this.mutate(async () => {
|
|
26632
26664
|
const state = await this.deps.loadState();
|
|
26665
|
+
const sessionIdentity = stableCoordinatorSession(transportSession);
|
|
26633
26666
|
const tasks = state.orchestration.tasks;
|
|
26634
26667
|
const bindings = state.orchestration.workerBindings;
|
|
26635
26668
|
const removedTaskIds = [];
|
|
26636
26669
|
for (const [taskId, task] of Object.entries(tasks)) {
|
|
26637
|
-
if (this.isTerminalStatus(task.status) && task.reviewPending === undefined && (task.coordinatorSession
|
|
26670
|
+
if (this.isTerminalStatus(task.status) && task.reviewPending === undefined && (sameCoordinatorSession(task.coordinatorSession, transportSession) || task.workerSession !== undefined && sameCoordinatorSession(task.workerSession, transportSession))) {
|
|
26638
26671
|
removedTaskIds.push(taskId);
|
|
26639
26672
|
}
|
|
26640
26673
|
}
|
|
@@ -26644,14 +26677,14 @@ class OrchestrationService {
|
|
|
26644
26677
|
const remainingWorkerSessions = new Set(Object.values(tasks).map((task) => task.workerSession).filter(Boolean));
|
|
26645
26678
|
let removedBindings = 0;
|
|
26646
26679
|
for (const [workerSession, binding] of Object.entries(bindings)) {
|
|
26647
|
-
const shouldPurgeBinding = workerSession
|
|
26680
|
+
const shouldPurgeBinding = sameCoordinatorSession(workerSession, transportSession) || sameCoordinatorSession(binding.coordinatorSession, transportSession);
|
|
26648
26681
|
if (shouldPurgeBinding && !remainingWorkerSessions.has(workerSession)) {
|
|
26649
26682
|
delete bindings[workerSession];
|
|
26650
26683
|
removedBindings += 1;
|
|
26651
26684
|
}
|
|
26652
26685
|
}
|
|
26653
|
-
const removedEmptyGroups = this.removeEmptyGroupsForCoordinator(state,
|
|
26654
|
-
const removedCoordinatorMetadata = this.removeCoordinatorMetadataIfUnused(state,
|
|
26686
|
+
const removedEmptyGroups = this.removeEmptyGroupsForCoordinator(state, sessionIdentity);
|
|
26687
|
+
const removedCoordinatorMetadata = this.removeCoordinatorMetadataIfUnused(state, sessionIdentity);
|
|
26655
26688
|
if (removedTaskIds.length > 0 || removedBindings > 0 || removedEmptyGroups || removedCoordinatorMetadata) {
|
|
26656
26689
|
await this.deps.saveState(state);
|
|
26657
26690
|
}
|
|
@@ -26661,106 +26694,28 @@ class OrchestrationService {
|
|
|
26661
26694
|
};
|
|
26662
26695
|
});
|
|
26663
26696
|
}
|
|
26664
|
-
async purgeExpiredResetCoordinators(input) {
|
|
26665
|
-
try {
|
|
26666
|
-
if (!Number.isFinite(input.cutoffDays) || input.cutoffDays < 0) {
|
|
26667
|
-
throw new Error(`cutoffDays must be a non-negative number, got ${String(input.cutoffDays)}`);
|
|
26668
|
-
}
|
|
26669
|
-
const result = await this.mutate(async () => {
|
|
26670
|
-
const state = await this.deps.loadState();
|
|
26671
|
-
const candidates = this.collectResetCoordinatorCandidates(state);
|
|
26672
|
-
const activeTransportSessions = new Set(Object.values(state.sessions).map((session3) => session3.transport_session));
|
|
26673
|
-
const MS_PER_DAY = 24 * 60 * 60 * 1000;
|
|
26674
|
-
const cutoffMs = input.cutoffDays * MS_PER_DAY;
|
|
26675
|
-
const nowMs = this.deps.now().getTime();
|
|
26676
|
-
let purgedCoordinators = 0;
|
|
26677
|
-
const removed = {
|
|
26678
|
-
tasks: 0,
|
|
26679
|
-
workerBindings: 0,
|
|
26680
|
-
groups: 0,
|
|
26681
|
-
coordinatorRoutes: 0,
|
|
26682
|
-
humanQuestionPackages: 0,
|
|
26683
|
-
coordinatorQuestionState: 0
|
|
26684
|
-
};
|
|
26685
|
-
for (const coordinatorSession of candidates) {
|
|
26686
|
-
if (activeTransportSessions.has(coordinatorSession)) {
|
|
26687
|
-
continue;
|
|
26688
|
-
}
|
|
26689
|
-
const activityAtMs = this.resolveResetCoordinatorActivityAtMs(state, coordinatorSession);
|
|
26690
|
-
if (activityAtMs === null) {
|
|
26691
|
-
continue;
|
|
26692
|
-
}
|
|
26693
|
-
if (nowMs - activityAtMs <= cutoffMs) {
|
|
26694
|
-
continue;
|
|
26695
|
-
}
|
|
26696
|
-
const delta = this.cascadeRemoveCoordinatorRecords(state, coordinatorSession);
|
|
26697
|
-
const changed = delta.tasks > 0 || delta.workerBindings > 0 || delta.groups > 0 || delta.coordinatorRoutes > 0 || delta.humanQuestionPackages > 0 || delta.coordinatorQuestionState > 0;
|
|
26698
|
-
if (!changed) {
|
|
26699
|
-
continue;
|
|
26700
|
-
}
|
|
26701
|
-
purgedCoordinators += 1;
|
|
26702
|
-
removed.tasks += delta.tasks;
|
|
26703
|
-
removed.workerBindings += delta.workerBindings;
|
|
26704
|
-
removed.groups += delta.groups;
|
|
26705
|
-
removed.coordinatorRoutes += delta.coordinatorRoutes;
|
|
26706
|
-
removed.humanQuestionPackages += delta.humanQuestionPackages;
|
|
26707
|
-
removed.coordinatorQuestionState += delta.coordinatorQuestionState;
|
|
26708
|
-
}
|
|
26709
|
-
const removedAny = removed.tasks > 0 || removed.workerBindings > 0 || removed.groups > 0 || removed.coordinatorRoutes > 0 || removed.humanQuestionPackages > 0 || removed.coordinatorQuestionState > 0;
|
|
26710
|
-
if (removedAny) {
|
|
26711
|
-
await this.deps.saveState(state);
|
|
26712
|
-
}
|
|
26713
|
-
return {
|
|
26714
|
-
candidates: candidates.length,
|
|
26715
|
-
purgedCoordinators,
|
|
26716
|
-
removed
|
|
26717
|
-
};
|
|
26718
|
-
});
|
|
26719
|
-
if (this.deps.logger) {
|
|
26720
|
-
this.deps.logger.info("orchestration.reset_gc.completed", "reset coordinator gc completed", {
|
|
26721
|
-
trigger: input.trigger,
|
|
26722
|
-
cutoffDays: input.cutoffDays,
|
|
26723
|
-
candidates: result.candidates,
|
|
26724
|
-
purgedCoordinators: result.purgedCoordinators,
|
|
26725
|
-
deletedCounts: result.removed
|
|
26726
|
-
});
|
|
26727
|
-
}
|
|
26728
|
-
return result;
|
|
26729
|
-
} catch (error2) {
|
|
26730
|
-
const logger2 = this.deps.logger;
|
|
26731
|
-
if (logger2) {
|
|
26732
|
-
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
26733
|
-
logger2.error("orchestration.reset_gc.failed", "reset coordinator gc failed", {
|
|
26734
|
-
trigger: input.trigger,
|
|
26735
|
-
cutoffDays: input.cutoffDays,
|
|
26736
|
-
message
|
|
26737
|
-
});
|
|
26738
|
-
}
|
|
26739
|
-
throw error2;
|
|
26740
|
-
}
|
|
26741
|
-
}
|
|
26742
26697
|
async listPendingCoordinatorResults(coordinatorSession) {
|
|
26743
26698
|
const state = await this.deps.loadState();
|
|
26744
26699
|
if (this.isExternalCoordinatorSession(state, coordinatorSession)) {
|
|
26745
26700
|
return [];
|
|
26746
26701
|
}
|
|
26747
|
-
return Object.values(state.orchestration.tasks).filter((task) => task.coordinatorSession
|
|
26702
|
+
return Object.values(state.orchestration.tasks).filter((task) => sameCoordinatorSession(task.coordinatorSession, coordinatorSession) && this.canInjectTaskIntoCoordinator(state, task) && (task.injectionPending === true || task.coordinatorInjectedAt === undefined)).sort((left, right) => left.updatedAt.localeCompare(right.updatedAt)).map((task) => ({ ...task }));
|
|
26748
26703
|
}
|
|
26749
26704
|
async listPendingCoordinatorBlockers(coordinatorSession) {
|
|
26750
26705
|
const state = await this.deps.loadState();
|
|
26751
26706
|
if (this.isExternalCoordinatorSession(state, coordinatorSession)) {
|
|
26752
26707
|
return [];
|
|
26753
26708
|
}
|
|
26754
|
-
const coordinatorState = state.orchestration.coordinatorQuestionState[coordinatorSession];
|
|
26709
|
+
const coordinatorState = state.orchestration.coordinatorQuestionState[stableCoordinatorSession(coordinatorSession)];
|
|
26755
26710
|
const hiddenQueuedQuestionKeys = coordinatorState?.activePackageId ? new Set((coordinatorState.queuedQuestions ?? []).map((entry) => `${entry.taskId}:${entry.questionId}`)) : null;
|
|
26756
|
-
return Object.values(state.orchestration.tasks).filter((task) => task.coordinatorSession
|
|
26711
|
+
return Object.values(state.orchestration.tasks).filter((task) => sameCoordinatorSession(task.coordinatorSession, coordinatorSession) && task.status === "blocked" && task.openQuestion?.status === "open" && !hiddenQueuedQuestionKeys?.has(`${task.taskId}:${task.openQuestion.questionId}`)).sort((left, right) => left.updatedAt.localeCompare(right.updatedAt)).map((task) => ({ ...task }));
|
|
26757
26712
|
}
|
|
26758
26713
|
async listContestedCoordinatorResults(coordinatorSession) {
|
|
26759
26714
|
const state = await this.deps.loadState();
|
|
26760
26715
|
if (this.isExternalCoordinatorSession(state, coordinatorSession)) {
|
|
26761
26716
|
return [];
|
|
26762
26717
|
}
|
|
26763
|
-
return Object.values(state.orchestration.tasks).filter((task) => task.coordinatorSession
|
|
26718
|
+
return Object.values(state.orchestration.tasks).filter((task) => sameCoordinatorSession(task.coordinatorSession, coordinatorSession) && task.reviewPending !== undefined).sort((left, right) => left.updatedAt.localeCompare(right.updatedAt)).map((task) => ({ ...task }));
|
|
26764
26719
|
}
|
|
26765
26720
|
async listPendingCoordinatorGroups(coordinatorSession) {
|
|
26766
26721
|
const state = await this.deps.loadState();
|
|
@@ -26769,7 +26724,7 @@ class OrchestrationService {
|
|
|
26769
26724
|
}
|
|
26770
26725
|
const groups = this.ensureGroups(state);
|
|
26771
26726
|
const tasks = Object.values(state.orchestration.tasks);
|
|
26772
|
-
return Object.values(groups).filter((group) => group.coordinatorSession
|
|
26727
|
+
return Object.values(groups).filter((group) => sameCoordinatorSession(group.coordinatorSession, coordinatorSession)).filter((group) => {
|
|
26773
26728
|
const groupTasks = tasks.filter((task) => task.groupId === group.groupId);
|
|
26774
26729
|
return this.canInjectGroupIntoCoordinator(state, group.groupId, groupTasks);
|
|
26775
26730
|
}).sort((left, right) => left.updatedAt.localeCompare(right.updatedAt)).map((group) => ({ ...group }));
|
|
@@ -26984,7 +26939,7 @@ class OrchestrationService {
|
|
|
26984
26939
|
if (input.sourceHandle !== undefined && task.sourceHandle !== input.sourceHandle) {
|
|
26985
26940
|
throw new Error(`task "${input.taskId}" belongs to source "${task.sourceHandle}", not "${input.sourceHandle}"`);
|
|
26986
26941
|
}
|
|
26987
|
-
if (input.coordinatorSession !== undefined && task.coordinatorSession
|
|
26942
|
+
if (input.coordinatorSession !== undefined && !sameCoordinatorSession(task.coordinatorSession, input.coordinatorSession)) {
|
|
26988
26943
|
throw new Error(`task "${input.taskId}" belongs to coordinator "${task.coordinatorSession}", not "${input.coordinatorSession}"`);
|
|
26989
26944
|
}
|
|
26990
26945
|
if (this.isTerminalStatus(task.status)) {
|
|
@@ -27411,11 +27366,11 @@ class OrchestrationService {
|
|
|
27411
27366
|
...binding.cwd ? { cwd: binding.cwd } : {}
|
|
27412
27367
|
};
|
|
27413
27368
|
}
|
|
27414
|
-
const coordinatorSession = Object.values(state.sessions).find((session3) => session3.transport_session
|
|
27369
|
+
const coordinatorSession = Object.values(state.sessions).find((session3) => sameCoordinatorSession(session3.transport_session, sourceHandle));
|
|
27415
27370
|
if (coordinatorSession) {
|
|
27416
27371
|
return {
|
|
27417
27372
|
sourceKind: "coordinator",
|
|
27418
|
-
coordinatorSession: sourceHandle,
|
|
27373
|
+
coordinatorSession: stableCoordinatorSession(sourceHandle),
|
|
27419
27374
|
workspace: coordinatorSession.workspace
|
|
27420
27375
|
};
|
|
27421
27376
|
}
|
|
@@ -27453,7 +27408,7 @@ class OrchestrationService {
|
|
|
27453
27408
|
if (role && policy.allowedAgentRequestRoles.length > 0 && !policy.allowedAgentRequestRoles.includes(role)) {
|
|
27454
27409
|
throw new Error(`role "${role}" is not allowed for agent-requested delegation`);
|
|
27455
27410
|
}
|
|
27456
|
-
const outstandingRequests = Object.values(state.orchestration.tasks).filter((task) => task.coordinatorSession
|
|
27411
|
+
const outstandingRequests = Object.values(state.orchestration.tasks).filter((task) => sameCoordinatorSession(task.coordinatorSession, coordinatorSession) && task.sourceKind !== "human" && (task.status === "needs_confirmation" || task.status === "running" || task.status === "queued"));
|
|
27457
27412
|
if (outstandingRequests.length >= policy.maxPendingAgentRequestsPerCoordinator) {
|
|
27458
27413
|
throw new Error("agent-requested delegation quota exceeded for this coordinator");
|
|
27459
27414
|
}
|
|
@@ -27557,13 +27512,13 @@ class OrchestrationService {
|
|
|
27557
27512
|
if (!filter) {
|
|
27558
27513
|
return true;
|
|
27559
27514
|
}
|
|
27560
|
-
return (filter.sourceHandle === undefined || task.sourceHandle === filter.sourceHandle) && (filter.coordinatorSession === undefined || task.coordinatorSession
|
|
27515
|
+
return (filter.sourceHandle === undefined || task.sourceHandle === filter.sourceHandle) && (filter.coordinatorSession === undefined || sameCoordinatorSession(task.coordinatorSession, filter.coordinatorSession)) && (filter.workspace === undefined || task.workspace === filter.workspace) && (filter.targetAgent === undefined || task.targetAgent === filter.targetAgent) && (filter.role === undefined || task.role === filter.role) && (filter.status === undefined || task.status === filter.status);
|
|
27561
27516
|
}
|
|
27562
27517
|
isTerminalStatus(status) {
|
|
27563
27518
|
return status === "completed" || status === "failed" || status === "cancelled";
|
|
27564
27519
|
}
|
|
27565
27520
|
assertCoordinatorOwnership(task, coordinatorSession) {
|
|
27566
|
-
if (task.coordinatorSession
|
|
27521
|
+
if (!sameCoordinatorSession(task.coordinatorSession, coordinatorSession)) {
|
|
27567
27522
|
throw new Error(`task "${task.taskId}" belongs to coordinator "${task.coordinatorSession}", not "${coordinatorSession}"`);
|
|
27568
27523
|
}
|
|
27569
27524
|
}
|
|
@@ -27576,7 +27531,7 @@ class OrchestrationService {
|
|
|
27576
27531
|
if (!group) {
|
|
27577
27532
|
throw new Error(`group "${groupId}" does not exist`);
|
|
27578
27533
|
}
|
|
27579
|
-
if (group.coordinatorSession
|
|
27534
|
+
if (!sameCoordinatorSession(group.coordinatorSession, coordinatorSession)) {
|
|
27580
27535
|
throw new Error(`group "${groupId}" belongs to coordinator "${group.coordinatorSession}", not "${coordinatorSession}"`);
|
|
27581
27536
|
}
|
|
27582
27537
|
}
|
|
@@ -27587,13 +27542,14 @@ class OrchestrationService {
|
|
|
27587
27542
|
return state.orchestration.humanQuestionPackages;
|
|
27588
27543
|
}
|
|
27589
27544
|
ensureCoordinatorQuestionState(state, coordinatorSession) {
|
|
27545
|
+
const key = stableCoordinatorSession(coordinatorSession);
|
|
27590
27546
|
if (!("coordinatorQuestionState" in state.orchestration) || !state.orchestration.coordinatorQuestionState) {
|
|
27591
27547
|
state.orchestration.coordinatorQuestionState = {};
|
|
27592
27548
|
}
|
|
27593
|
-
state.orchestration.coordinatorQuestionState[
|
|
27549
|
+
state.orchestration.coordinatorQuestionState[key] ??= {
|
|
27594
27550
|
queuedQuestions: []
|
|
27595
27551
|
};
|
|
27596
|
-
return state.orchestration.coordinatorQuestionState[
|
|
27552
|
+
return state.orchestration.coordinatorQuestionState[key];
|
|
27597
27553
|
}
|
|
27598
27554
|
ensureCoordinatorRoutes(state) {
|
|
27599
27555
|
if (!("coordinatorRoutes" in state.orchestration) || !state.orchestration.coordinatorRoutes) {
|
|
@@ -27774,7 +27730,7 @@ class OrchestrationService {
|
|
|
27774
27730
|
const referencedGroupIds = new Set(Object.values(state.orchestration.tasks).map((task) => task.groupId).filter((groupId) => typeof groupId === "string"));
|
|
27775
27731
|
let removedAny = false;
|
|
27776
27732
|
for (const [groupId, group] of Object.entries(groups)) {
|
|
27777
|
-
if (group.coordinatorSession
|
|
27733
|
+
if (!sameCoordinatorSession(group.coordinatorSession, coordinatorSession)) {
|
|
27778
27734
|
continue;
|
|
27779
27735
|
}
|
|
27780
27736
|
if (!referencedGroupIds.has(groupId)) {
|
|
@@ -27785,125 +27741,30 @@ class OrchestrationService {
|
|
|
27785
27741
|
return removedAny;
|
|
27786
27742
|
}
|
|
27787
27743
|
removeCoordinatorMetadataIfUnused(state, coordinatorSession) {
|
|
27788
|
-
const
|
|
27789
|
-
const
|
|
27744
|
+
const key = stableCoordinatorSession(coordinatorSession);
|
|
27745
|
+
const hasCoordinatorTasks = Object.values(state.orchestration.tasks).some((task) => sameCoordinatorSession(task.coordinatorSession, coordinatorSession));
|
|
27746
|
+
const hasCoordinatorBindings = Object.values(state.orchestration.workerBindings).some((binding) => sameCoordinatorSession(binding.coordinatorSession, coordinatorSession));
|
|
27790
27747
|
if (hasCoordinatorTasks || hasCoordinatorBindings) {
|
|
27791
27748
|
return false;
|
|
27792
27749
|
}
|
|
27793
27750
|
let removedAny = false;
|
|
27794
27751
|
const packages = this.ensureHumanQuestionPackages(state);
|
|
27795
27752
|
for (const [packageId, packageRecord] of Object.entries(packages)) {
|
|
27796
|
-
if (packageRecord.coordinatorSession
|
|
27753
|
+
if (sameCoordinatorSession(packageRecord.coordinatorSession, coordinatorSession)) {
|
|
27797
27754
|
delete packages[packageId];
|
|
27798
27755
|
removedAny = true;
|
|
27799
27756
|
}
|
|
27800
27757
|
}
|
|
27801
|
-
if (state.orchestration.coordinatorQuestionState?.[
|
|
27802
|
-
delete state.orchestration.coordinatorQuestionState[
|
|
27758
|
+
if (state.orchestration.coordinatorQuestionState?.[key] !== undefined) {
|
|
27759
|
+
delete state.orchestration.coordinatorQuestionState[key];
|
|
27803
27760
|
removedAny = true;
|
|
27804
27761
|
}
|
|
27805
|
-
if (state.orchestration.coordinatorRoutes?.[
|
|
27806
|
-
delete state.orchestration.coordinatorRoutes[
|
|
27762
|
+
if (state.orchestration.coordinatorRoutes?.[key] !== undefined) {
|
|
27763
|
+
delete state.orchestration.coordinatorRoutes[key];
|
|
27807
27764
|
removedAny = true;
|
|
27808
27765
|
}
|
|
27809
27766
|
return removedAny;
|
|
27810
27767
|
}
|
|
27811
|
-
isResetCoordinatorSession(coordinatorSession) {
|
|
27812
|
-
return coordinatorSession.includes(":reset-");
|
|
27813
|
-
}
|
|
27814
|
-
collectResetCoordinatorCandidates(state) {
|
|
27815
|
-
const candidates = new Set;
|
|
27816
|
-
for (const coordinatorSession of Object.keys(state.orchestration.coordinatorRoutes ?? {})) {
|
|
27817
|
-
if (this.isResetCoordinatorSession(coordinatorSession)) {
|
|
27818
|
-
candidates.add(coordinatorSession);
|
|
27819
|
-
}
|
|
27820
|
-
}
|
|
27821
|
-
for (const task of Object.values(state.orchestration.tasks ?? {})) {
|
|
27822
|
-
if (this.isResetCoordinatorSession(task.coordinatorSession)) {
|
|
27823
|
-
candidates.add(task.coordinatorSession);
|
|
27824
|
-
}
|
|
27825
|
-
}
|
|
27826
|
-
return [...candidates];
|
|
27827
|
-
}
|
|
27828
|
-
parseDateMs(value) {
|
|
27829
|
-
if (!value) {
|
|
27830
|
-
return null;
|
|
27831
|
-
}
|
|
27832
|
-
const ms = new Date(value).getTime();
|
|
27833
|
-
return Number.isFinite(ms) ? ms : null;
|
|
27834
|
-
}
|
|
27835
|
-
resolveResetCoordinatorActivityAtMs(state, coordinatorSession) {
|
|
27836
|
-
const routeUpdatedAt = state.orchestration.coordinatorRoutes?.[coordinatorSession]?.updatedAt;
|
|
27837
|
-
const routeMs = this.parseDateMs(routeUpdatedAt);
|
|
27838
|
-
let tasksMs = null;
|
|
27839
|
-
for (const task of Object.values(state.orchestration.tasks ?? {})) {
|
|
27840
|
-
if (task.coordinatorSession !== coordinatorSession) {
|
|
27841
|
-
continue;
|
|
27842
|
-
}
|
|
27843
|
-
const candidate = this.parseDateMs(task.updatedAt);
|
|
27844
|
-
if (candidate === null) {
|
|
27845
|
-
continue;
|
|
27846
|
-
}
|
|
27847
|
-
tasksMs = tasksMs === null ? candidate : Math.max(tasksMs, candidate);
|
|
27848
|
-
}
|
|
27849
|
-
if (routeMs === null && tasksMs === null) {
|
|
27850
|
-
return null;
|
|
27851
|
-
}
|
|
27852
|
-
if (routeMs === null) {
|
|
27853
|
-
return tasksMs;
|
|
27854
|
-
}
|
|
27855
|
-
if (tasksMs === null) {
|
|
27856
|
-
return routeMs;
|
|
27857
|
-
}
|
|
27858
|
-
return Math.max(routeMs, tasksMs);
|
|
27859
|
-
}
|
|
27860
|
-
cascadeRemoveCoordinatorRecords(state, coordinatorSession) {
|
|
27861
|
-
const removed = {
|
|
27862
|
-
tasks: 0,
|
|
27863
|
-
workerBindings: 0,
|
|
27864
|
-
groups: 0,
|
|
27865
|
-
coordinatorRoutes: 0,
|
|
27866
|
-
humanQuestionPackages: 0,
|
|
27867
|
-
coordinatorQuestionState: 0
|
|
27868
|
-
};
|
|
27869
|
-
const tasks = state.orchestration.tasks;
|
|
27870
|
-
for (const [taskId, task] of Object.entries(tasks ?? {})) {
|
|
27871
|
-
if (task.coordinatorSession === coordinatorSession) {
|
|
27872
|
-
delete tasks[taskId];
|
|
27873
|
-
removed.tasks += 1;
|
|
27874
|
-
}
|
|
27875
|
-
}
|
|
27876
|
-
const workerBindings = state.orchestration.workerBindings;
|
|
27877
|
-
for (const [workerSession, binding] of Object.entries(workerBindings ?? {})) {
|
|
27878
|
-
if (binding.coordinatorSession === coordinatorSession) {
|
|
27879
|
-
delete workerBindings[workerSession];
|
|
27880
|
-
removed.workerBindings += 1;
|
|
27881
|
-
}
|
|
27882
|
-
}
|
|
27883
|
-
const groups = this.ensureGroups(state);
|
|
27884
|
-
for (const [groupId, group] of Object.entries(groups ?? {})) {
|
|
27885
|
-
if (group.coordinatorSession === coordinatorSession) {
|
|
27886
|
-
delete groups[groupId];
|
|
27887
|
-
removed.groups += 1;
|
|
27888
|
-
}
|
|
27889
|
-
}
|
|
27890
|
-
if (state.orchestration.coordinatorRoutes?.[coordinatorSession] !== undefined) {
|
|
27891
|
-
delete state.orchestration.coordinatorRoutes[coordinatorSession];
|
|
27892
|
-
removed.coordinatorRoutes += 1;
|
|
27893
|
-
}
|
|
27894
|
-
const packages = this.ensureHumanQuestionPackages(state);
|
|
27895
|
-
for (const [packageId, packageRecord] of Object.entries(packages ?? {})) {
|
|
27896
|
-
if (packageRecord.coordinatorSession === coordinatorSession) {
|
|
27897
|
-
delete packages[packageId];
|
|
27898
|
-
removed.humanQuestionPackages += 1;
|
|
27899
|
-
}
|
|
27900
|
-
}
|
|
27901
|
-
if (state.orchestration.coordinatorQuestionState?.[coordinatorSession] !== undefined) {
|
|
27902
|
-
delete state.orchestration.coordinatorQuestionState[coordinatorSession];
|
|
27903
|
-
removed.coordinatorQuestionState += 1;
|
|
27904
|
-
}
|
|
27905
|
-
return removed;
|
|
27906
|
-
}
|
|
27907
27768
|
bumpGroupUpdated(state, groupId, now) {
|
|
27908
27769
|
if (!groupId) {
|
|
27909
27770
|
return;
|
|
@@ -28077,7 +27938,7 @@ class OrchestrationService {
|
|
|
28077
27938
|
}
|
|
28078
27939
|
const validQueuedQuestions = coordinatorState.queuedQuestions.filter((entry) => {
|
|
28079
27940
|
const task = state.orchestration.tasks[entry.taskId];
|
|
28080
|
-
return task
|
|
27941
|
+
return task !== undefined && sameCoordinatorSession(task.coordinatorSession, coordinatorSession) && task.status === "blocked" && task.openQuestion?.status === "open" && task.openQuestion.questionId === entry.questionId;
|
|
28081
27942
|
});
|
|
28082
27943
|
if (validQueuedQuestions.length !== coordinatorState.queuedQuestions.length) {
|
|
28083
27944
|
coordinatorState.queuedQuestions = validQueuedQuestions;
|
|
@@ -28566,7 +28427,7 @@ async function createScheduledTaskFromRoute(input, deps) {
|
|
|
28566
28427
|
if (coordinatorSession.length === 0) {
|
|
28567
28428
|
throw new Error("coordinatorSession must be a non-empty string");
|
|
28568
28429
|
}
|
|
28569
|
-
const route = deps.state.orchestration.coordinatorRoutes[coordinatorSession];
|
|
28430
|
+
const route = deps.state.orchestration.coordinatorRoutes[stableCoordinatorSession(coordinatorSession)];
|
|
28570
28431
|
if (!route) {
|
|
28571
28432
|
throw new Error(`no chat route is recorded for coordinator session "${coordinatorSession}"`);
|
|
28572
28433
|
}
|
|
@@ -28593,7 +28454,7 @@ async function createScheduledTaskFromRoute(input, deps) {
|
|
|
28593
28454
|
if (!session3) {
|
|
28594
28455
|
throw new Error(`session "${route.sessionAlias}" recorded for coordinator session "${coordinatorSession}" was not found`);
|
|
28595
28456
|
}
|
|
28596
|
-
if (session3.transportSession
|
|
28457
|
+
if (!sameCoordinatorSession(session3.transportSession, coordinatorSession)) {
|
|
28597
28458
|
throw new Error(`session "${route.sessionAlias}" is no longer attached to coordinator session "${coordinatorSession}"`);
|
|
28598
28459
|
}
|
|
28599
28460
|
const executeAt = parseRouteScheduledTime(input.timeText, deps.now?.() ?? new Date);
|
|
@@ -28659,7 +28520,7 @@ function resolveOwnedCoordinatorRoute(coordinatorSession, state, label) {
|
|
|
28659
28520
|
if (session3.length === 0) {
|
|
28660
28521
|
throw new Error("coordinatorSession must be a non-empty string");
|
|
28661
28522
|
}
|
|
28662
|
-
const route = state.orchestration.coordinatorRoutes[session3];
|
|
28523
|
+
const route = state.orchestration.coordinatorRoutes[stableCoordinatorSession(session3)];
|
|
28663
28524
|
if (!route) {
|
|
28664
28525
|
throw new Error(`no chat route is recorded for coordinator session "${session3}"`);
|
|
28665
28526
|
}
|
|
@@ -28751,9 +28612,10 @@ class SessionService {
|
|
|
28751
28612
|
return this.state.chat_contexts[chatKey]?.current_session;
|
|
28752
28613
|
}
|
|
28753
28614
|
async getPreferredSessionForTransport(transportSession) {
|
|
28754
|
-
const
|
|
28755
|
-
const
|
|
28756
|
-
const
|
|
28615
|
+
const target = stableCoordinatorSession(transportSession);
|
|
28616
|
+
const matches = Object.values(this.state.sessions).filter((session3) => stableCoordinatorSession(session3.transport_session) === target).sort((left, right) => right.last_used_at.localeCompare(left.last_used_at));
|
|
28617
|
+
const expectedAlias = target.split(":").at(-1);
|
|
28618
|
+
const expectedWorkspace = target.split(":")[0];
|
|
28757
28619
|
const preferred = matches.find((session3) => session3.alias === expectedAlias && session3.workspace === expectedWorkspace) ?? matches[0];
|
|
28758
28620
|
return preferred ? this.toResolvedSession(preferred) : null;
|
|
28759
28621
|
}
|
|
@@ -29305,7 +29167,6 @@ async function runConsole(paths, deps) {
|
|
|
29305
29167
|
let runtime = null;
|
|
29306
29168
|
let consumerLock;
|
|
29307
29169
|
let heartbeatTimer = null;
|
|
29308
|
-
let gcResetTimer = null;
|
|
29309
29170
|
let consumerLockAcquired = false;
|
|
29310
29171
|
let daemonRuntimeStarted = false;
|
|
29311
29172
|
const shutdownController = new AbortController;
|
|
@@ -29319,12 +29180,6 @@ async function runConsole(paths, deps) {
|
|
|
29319
29180
|
if (deps.afterBuild) {
|
|
29320
29181
|
await deps.afterBuild(runtime);
|
|
29321
29182
|
}
|
|
29322
|
-
try {
|
|
29323
|
-
await runtime.orchestration.service.purgeExpiredResetCoordinators({
|
|
29324
|
-
cutoffDays: 7,
|
|
29325
|
-
trigger: "startup"
|
|
29326
|
-
});
|
|
29327
|
-
} catch {}
|
|
29328
29183
|
try {
|
|
29329
29184
|
await runtime.orchestration.service.reconcileParallelSlots();
|
|
29330
29185
|
} catch (reconcileError) {
|
|
@@ -29380,6 +29235,7 @@ async function runConsole(paths, deps) {
|
|
|
29380
29235
|
throw error2;
|
|
29381
29236
|
}
|
|
29382
29237
|
}
|
|
29238
|
+
await runtime.reapStaleQueueOwners();
|
|
29383
29239
|
if (deps.beforeReady) {
|
|
29384
29240
|
await deps.beforeReady(runtime);
|
|
29385
29241
|
}
|
|
@@ -29393,10 +29249,6 @@ async function runConsole(paths, deps) {
|
|
|
29393
29249
|
heartbeatTimer = setIntervalFn(() => {
|
|
29394
29250
|
deps.daemonRuntime?.heartbeat().catch(() => {});
|
|
29395
29251
|
}, deps.heartbeatIntervalMs ?? 30000);
|
|
29396
|
-
const runtimeForGc = runtime;
|
|
29397
|
-
gcResetTimer = setIntervalFn(() => {
|
|
29398
|
-
runtimeForGc.orchestration.service.purgeExpiredResetCoordinators({ cutoffDays: 7, trigger: "interval" }).catch(() => {});
|
|
29399
|
-
}, 86400000);
|
|
29400
29252
|
}
|
|
29401
29253
|
const channelStartPromise = deps.channels.startAll({
|
|
29402
29254
|
agent: runtime.agent,
|
|
@@ -29451,7 +29303,6 @@ async function runConsole(paths, deps) {
|
|
|
29451
29303
|
signalHandler,
|
|
29452
29304
|
clearIntervalFn,
|
|
29453
29305
|
heartbeatTimer,
|
|
29454
|
-
gcResetTimer,
|
|
29455
29306
|
...deps.daemonRuntime ? { daemonRuntime: deps.daemonRuntime } : {},
|
|
29456
29307
|
runtime,
|
|
29457
29308
|
consumerLock,
|
|
@@ -29477,9 +29328,6 @@ async function runCleanupSequence(input) {
|
|
|
29477
29328
|
if (input.heartbeatTimer !== null) {
|
|
29478
29329
|
input.clearIntervalFn(input.heartbeatTimer);
|
|
29479
29330
|
}
|
|
29480
|
-
if (input.gcResetTimer !== null) {
|
|
29481
|
-
input.clearIntervalFn(input.gcResetTimer);
|
|
29482
|
-
}
|
|
29483
29331
|
if (input.daemonRuntime && input.runtime) {
|
|
29484
29332
|
try {
|
|
29485
29333
|
await input.runtime.orchestration.server.stop();
|
|
@@ -31503,6 +31351,17 @@ var init_queue_owner_reaper = __esm(() => {
|
|
|
31503
31351
|
});
|
|
31504
31352
|
|
|
31505
31353
|
// src/transport/collect-reap-targets.ts
|
|
31354
|
+
function collectReapTargets(sessions, orchestration3, config4) {
|
|
31355
|
+
return [
|
|
31356
|
+
...sessions.listAllResolvedSessions().map((session3) => ({
|
|
31357
|
+
agent: session3.agent,
|
|
31358
|
+
...session3.agentCommand ? { agentCommand: session3.agentCommand } : {},
|
|
31359
|
+
cwd: session3.cwd,
|
|
31360
|
+
transportSession: session3.transportSession
|
|
31361
|
+
})),
|
|
31362
|
+
...workerBindingReapTargets(orchestration3, config4)
|
|
31363
|
+
];
|
|
31364
|
+
}
|
|
31506
31365
|
function workerBindingReapTargets(orchestration3, config4) {
|
|
31507
31366
|
const targets = [];
|
|
31508
31367
|
for (const [workerSession, binding] of Object.entries(orchestration3.workerBindings)) {
|
|
@@ -32224,7 +32083,7 @@ async function buildApp(paths, deps = {}) {
|
|
|
32224
32083
|
}
|
|
32225
32084
|
},
|
|
32226
32085
|
findReusableWorkerSession: async ({ coordinatorSession, workspace: workspace3, cwd, targetAgent, role }) => {
|
|
32227
|
-
const binding = Object.entries(state.orchestration.workerBindings).find(([, current]) => current.ephemeral !== true && current.coordinatorSession
|
|
32086
|
+
const binding = Object.entries(state.orchestration.workerBindings).find(([, current]) => current.ephemeral !== true && sameCoordinatorSession(current.coordinatorSession, coordinatorSession) && current.workspace === workspace3 && current.cwd === cwd && current.targetAgent === targetAgent && current.role === role);
|
|
32228
32087
|
return binding?.[0] ?? null;
|
|
32229
32088
|
},
|
|
32230
32089
|
logger: logger2
|
|
@@ -32282,6 +32141,33 @@ async function buildApp(paths, deps = {}) {
|
|
|
32282
32141
|
}),
|
|
32283
32142
|
logger: logger2
|
|
32284
32143
|
});
|
|
32144
|
+
const reapWarmQueueOwners = async (phase) => {
|
|
32145
|
+
try {
|
|
32146
|
+
const targets = collectReapTargets(sessions, state.orchestration, config4);
|
|
32147
|
+
if (targets.length === 0) {
|
|
32148
|
+
return;
|
|
32149
|
+
}
|
|
32150
|
+
const { terminated, attempted } = await reapQueueOwners(acpxCommand, targets, {
|
|
32151
|
+
onError: (target, error2) => {
|
|
32152
|
+
logger2.info("transport.queue_owner_reap.failed", "failed to reap queue owner", {
|
|
32153
|
+
phase,
|
|
32154
|
+
transport_session: target.transportSession,
|
|
32155
|
+
error: error2 instanceof Error ? error2.message : String(error2)
|
|
32156
|
+
}).catch(() => {});
|
|
32157
|
+
}
|
|
32158
|
+
});
|
|
32159
|
+
await logger2.info("transport.queue_owner_reap.completed", "reaped warm queue owners", {
|
|
32160
|
+
phase,
|
|
32161
|
+
terminated,
|
|
32162
|
+
attempted
|
|
32163
|
+
}).catch(() => {});
|
|
32164
|
+
} catch (err) {
|
|
32165
|
+
await logger2.error("transport.queue_owner_reap.error", "queue owner reap failed", {
|
|
32166
|
+
phase,
|
|
32167
|
+
error: err instanceof Error ? err.message : String(err)
|
|
32168
|
+
}).catch(() => {});
|
|
32169
|
+
}
|
|
32170
|
+
};
|
|
32285
32171
|
return {
|
|
32286
32172
|
agent: agent3,
|
|
32287
32173
|
router: router3,
|
|
@@ -32302,41 +32188,14 @@ async function buildApp(paths, deps = {}) {
|
|
|
32302
32188
|
service: scheduledService,
|
|
32303
32189
|
scheduler: scheduledScheduler
|
|
32304
32190
|
},
|
|
32191
|
+
reapStaleQueueOwners: () => reapWarmQueueOwners("startup"),
|
|
32305
32192
|
dispose: async () => {
|
|
32306
32193
|
scheduledScheduler.stop();
|
|
32307
32194
|
if (progressHeartbeatInterval !== undefined) {
|
|
32308
32195
|
clearInterval(progressHeartbeatInterval);
|
|
32309
32196
|
}
|
|
32310
32197
|
await Promise.allSettled([...pendingWorkerDispatches]);
|
|
32311
|
-
|
|
32312
|
-
const targets = [
|
|
32313
|
-
...sessions.listAllResolvedSessions().map((session3) => ({
|
|
32314
|
-
agent: session3.agent,
|
|
32315
|
-
...session3.agentCommand ? { agentCommand: session3.agentCommand } : {},
|
|
32316
|
-
cwd: session3.cwd,
|
|
32317
|
-
transportSession: session3.transportSession
|
|
32318
|
-
})),
|
|
32319
|
-
...workerBindingReapTargets(state.orchestration, config4)
|
|
32320
|
-
];
|
|
32321
|
-
if (targets.length > 0) {
|
|
32322
|
-
const { terminated, attempted } = await reapQueueOwners(acpxCommand, targets, {
|
|
32323
|
-
onError: (target, error2) => {
|
|
32324
|
-
logger2.info("transport.queue_owner_reap.failed", "failed to reap queue owner on shutdown", {
|
|
32325
|
-
transport_session: target.transportSession,
|
|
32326
|
-
error: error2 instanceof Error ? error2.message : String(error2)
|
|
32327
|
-
}).catch(() => {});
|
|
32328
|
-
}
|
|
32329
|
-
});
|
|
32330
|
-
await logger2.info("transport.queue_owner_reap.completed", "reaped warm queue owners on shutdown", {
|
|
32331
|
-
terminated,
|
|
32332
|
-
attempted
|
|
32333
|
-
}).catch(() => {});
|
|
32334
|
-
}
|
|
32335
|
-
} catch (err) {
|
|
32336
|
-
await logger2.error("transport.queue_owner_reap.error", "queue owner reap failed during shutdown", {
|
|
32337
|
-
error: err instanceof Error ? err.message : String(err)
|
|
32338
|
-
}).catch(() => {});
|
|
32339
|
-
}
|
|
32198
|
+
await reapWarmQueueOwners("shutdown");
|
|
32340
32199
|
await debouncedStateStore.dispose();
|
|
32341
32200
|
if ("dispose" in transport && typeof transport.dispose === "function") {
|
|
32342
32201
|
await transport.dispose();
|
|
@@ -46059,6 +45918,9 @@ function requireHome(env) {
|
|
|
46059
45918
|
return home;
|
|
46060
45919
|
}
|
|
46061
45920
|
|
|
45921
|
+
// src/mcp/xacpx-mcp-server.ts
|
|
45922
|
+
init_endpoint_probe();
|
|
45923
|
+
|
|
46062
45924
|
// src/mcp/xacpx-mcp-tools.ts
|
|
46063
45925
|
init_task_watch_timeouts();
|
|
46064
45926
|
init_quota_errors();
|
|
@@ -46574,7 +46436,7 @@ function formatToolError(error2) {
|
|
|
46574
46436
|
init_orchestration_ipc();
|
|
46575
46437
|
init_task_watch_timeouts();
|
|
46576
46438
|
import { randomUUID } from "node:crypto";
|
|
46577
|
-
import { createConnection } from "node:net";
|
|
46439
|
+
import { createConnection as createConnection2 } from "node:net";
|
|
46578
46440
|
|
|
46579
46441
|
class OrchestrationClient {
|
|
46580
46442
|
endpoint;
|
|
@@ -46642,7 +46504,7 @@ class OrchestrationClient {
|
|
|
46642
46504
|
async request(method, params, timeoutMs = this.timeoutMs) {
|
|
46643
46505
|
const id = this.createId();
|
|
46644
46506
|
return await new Promise((resolve, reject) => {
|
|
46645
|
-
const socket =
|
|
46507
|
+
const socket = createConnection2(this.endpoint.path);
|
|
46646
46508
|
let buffer = "";
|
|
46647
46509
|
let settled = false;
|
|
46648
46510
|
let timer;
|
|
@@ -47285,7 +47147,9 @@ function installMcpStdioShutdownHooks(options) {
|
|
|
47285
47147
|
const setIntervalFn = options.setIntervalFn ?? ((callback, ms) => setInterval(callback, ms));
|
|
47286
47148
|
const clearIntervalFn = options.clearIntervalFn ?? ((handle) => clearInterval(handle));
|
|
47287
47149
|
const parentPid = options.parentPid ?? process.ppid;
|
|
47288
|
-
const parentCheckIntervalMs = options.parentCheckIntervalMs ??
|
|
47150
|
+
const parentCheckIntervalMs = options.parentCheckIntervalMs ?? parseIntervalMs(coreEnv("MCP_PARENT_CHECK_INTERVAL_MS"), 5000);
|
|
47151
|
+
const endpointCheckIntervalMs = options.endpointCheckIntervalMs ?? parseIntervalMs(coreEnv("MCP_ENDPOINT_CHECK_INTERVAL_MS"), 1e4);
|
|
47152
|
+
const endpointFailureThreshold = options.endpointFailureThreshold ?? 3;
|
|
47289
47153
|
let disposed = false;
|
|
47290
47154
|
let triggered = false;
|
|
47291
47155
|
const triggerShutdown = (reason, context) => {
|
|
@@ -47318,6 +47182,31 @@ function installMcpStdioShutdownHooks(options) {
|
|
|
47318
47182
|
}, parentCheckIntervalMs);
|
|
47319
47183
|
parentTimer.unref?.();
|
|
47320
47184
|
}
|
|
47185
|
+
let endpointTimer;
|
|
47186
|
+
const probeEndpoint = options.probeEndpoint;
|
|
47187
|
+
if (probeEndpoint && endpointCheckIntervalMs > 0 && endpointFailureThreshold > 0) {
|
|
47188
|
+
let consecutiveDead = 0;
|
|
47189
|
+
let probing = false;
|
|
47190
|
+
const runEndpointCheck = async () => {
|
|
47191
|
+
if (disposed || triggered || probing)
|
|
47192
|
+
return;
|
|
47193
|
+
probing = true;
|
|
47194
|
+
try {
|
|
47195
|
+
if (await probeEndpoint()) {
|
|
47196
|
+
consecutiveDead = 0;
|
|
47197
|
+
return;
|
|
47198
|
+
}
|
|
47199
|
+
consecutiveDead += 1;
|
|
47200
|
+
if (consecutiveDead >= endpointFailureThreshold) {
|
|
47201
|
+
triggerShutdown("daemon_endpoint_dead", { consecutiveFailures: consecutiveDead });
|
|
47202
|
+
}
|
|
47203
|
+
} catch {} finally {
|
|
47204
|
+
probing = false;
|
|
47205
|
+
}
|
|
47206
|
+
};
|
|
47207
|
+
endpointTimer = setIntervalFn(runEndpointCheck, endpointCheckIntervalMs);
|
|
47208
|
+
endpointTimer.unref?.();
|
|
47209
|
+
}
|
|
47321
47210
|
return () => {
|
|
47322
47211
|
if (disposed)
|
|
47323
47212
|
return;
|
|
@@ -47332,13 +47221,16 @@ function installMcpStdioShutdownHooks(options) {
|
|
|
47332
47221
|
if (parentTimer) {
|
|
47333
47222
|
clearIntervalFn(parentTimer);
|
|
47334
47223
|
}
|
|
47224
|
+
if (endpointTimer) {
|
|
47225
|
+
clearIntervalFn(endpointTimer);
|
|
47226
|
+
}
|
|
47335
47227
|
};
|
|
47336
47228
|
}
|
|
47337
|
-
function
|
|
47229
|
+
function parseIntervalMs(raw, fallback) {
|
|
47338
47230
|
if (raw === undefined || raw.trim().length === 0)
|
|
47339
|
-
return
|
|
47231
|
+
return fallback;
|
|
47340
47232
|
const parsed = Number(raw);
|
|
47341
|
-
return Number.isFinite(parsed) && parsed >= 0 ? parsed :
|
|
47233
|
+
return Number.isFinite(parsed) && parsed >= 0 ? parsed : fallback;
|
|
47342
47234
|
}
|
|
47343
47235
|
function errorContext(error2) {
|
|
47344
47236
|
const record3 = error2;
|
|
@@ -47357,7 +47249,8 @@ function defaultIsProcessRunning3(pid) {
|
|
|
47357
47249
|
}
|
|
47358
47250
|
}
|
|
47359
47251
|
async function runXacpxMcpServer(options) {
|
|
47360
|
-
const
|
|
47252
|
+
const endpoint = options.endpoint ?? resolveDefaultOrchestrationEndpoint(process.env, process.platform);
|
|
47253
|
+
const transport = options.transport ?? createOrchestrationTransport(endpoint);
|
|
47361
47254
|
const server = createXacpxMcpServer({
|
|
47362
47255
|
transport,
|
|
47363
47256
|
...options.coordinatorSession ? { coordinatorSession: options.coordinatorSession } : {},
|
|
@@ -47390,6 +47283,7 @@ async function runXacpxMcpServer(options) {
|
|
|
47390
47283
|
stdin,
|
|
47391
47284
|
stdout,
|
|
47392
47285
|
shutdown,
|
|
47286
|
+
probeEndpoint: () => canConnectToEndpoint(endpoint.path, 4000),
|
|
47393
47287
|
onDiagnostic: options.onDiagnostic
|
|
47394
47288
|
});
|
|
47395
47289
|
await server.connect(stdio);
|
|
@@ -47422,7 +47316,6 @@ function sanitizeMcpClientName(input) {
|
|
|
47422
47316
|
fallback: "mcp-host"
|
|
47423
47317
|
});
|
|
47424
47318
|
}
|
|
47425
|
-
|
|
47426
47319
|
// src/mcp/parse-string-flag.ts
|
|
47427
47320
|
function parseStringFlag(args, env, options) {
|
|
47428
47321
|
let fromFlag = null;
|
|
@@ -47658,7 +47551,6 @@ async function handleUpdateCli(args, deps) {
|
|
|
47658
47551
|
kind: "plugin",
|
|
47659
47552
|
name: plugin.name,
|
|
47660
47553
|
currentVersion: plugin.version,
|
|
47661
|
-
pinned: Boolean(plugin.version),
|
|
47662
47554
|
latestVersion: await latestOf(plugin.name)
|
|
47663
47555
|
});
|
|
47664
47556
|
}
|
|
@@ -47667,12 +47559,12 @@ async function handleUpdateCli(args, deps) {
|
|
|
47667
47559
|
const target = targets[index];
|
|
47668
47560
|
deps.print(`${index + 1}. ${formatTarget(target)}`);
|
|
47669
47561
|
}
|
|
47670
|
-
const unavailable = targets.filter((target) => !target.latestVersion
|
|
47562
|
+
const unavailable = targets.filter((target) => !target.latestVersion);
|
|
47671
47563
|
if (all && unavailable.length > 0) {
|
|
47672
47564
|
deps.print(t().cliUpdate.unavailableAborted(unavailable.map((target) => target.name).join(", ")));
|
|
47673
47565
|
return 1;
|
|
47674
47566
|
}
|
|
47675
|
-
const candidates = targets.filter((target) => target.latestVersion && (target.
|
|
47567
|
+
const candidates = targets.filter((target) => target.latestVersion && (target.successorPackage ? true : target.currentVersion !== target.latestVersion));
|
|
47676
47568
|
const selected = await selectTargets(targets, candidates, { all, explicitTarget: explicitTargets[0], deps });
|
|
47677
47569
|
if (!selected.ok) {
|
|
47678
47570
|
deps.print(selected.message);
|
|
@@ -47765,8 +47657,6 @@ async function selectTargets(targets, candidates, input) {
|
|
|
47765
47657
|
return { ok: false, message: t().cliUpdate.targetNotFound(input.explicitTarget), exitCode: 1 };
|
|
47766
47658
|
if (!target.latestVersion)
|
|
47767
47659
|
return { ok: false, message: t().cliUpdate.targetVersionUnknown(target.name), exitCode: 1 };
|
|
47768
|
-
if (target.kind === "plugin" && !target.pinned)
|
|
47769
|
-
return { ok: false, message: t().cliUpdate.targetNotPinned(target.name), exitCode: 1 };
|
|
47770
47660
|
if (!target.successorPackage && target.currentVersion === target.latestVersion)
|
|
47771
47661
|
return { ok: true, targets: [] };
|
|
47772
47662
|
return { ok: true, targets: [target] };
|
|
@@ -47790,8 +47680,6 @@ async function selectTargets(targets, candidates, input) {
|
|
|
47790
47680
|
const target = targets[index - 1];
|
|
47791
47681
|
if (!target.latestVersion)
|
|
47792
47682
|
return { ok: false, message: t().cliUpdate.targetVersionUnknown(target.name), exitCode: 1 };
|
|
47793
|
-
if (target.kind === "plugin" && !target.pinned)
|
|
47794
|
-
return { ok: false, message: t().cliUpdate.targetNotPinned(target.name), exitCode: 1 };
|
|
47795
47683
|
if (!target.successorPackage && target.currentVersion === target.latestVersion)
|
|
47796
47684
|
continue;
|
|
47797
47685
|
if (!selected.includes(target))
|
|
@@ -49205,7 +49093,7 @@ init_i18n();
|
|
|
49205
49093
|
init_bootstrap();
|
|
49206
49094
|
async function prepareMcpCoordinatorStartup(input) {
|
|
49207
49095
|
const coordinatorSession = input.coordinatorSession.trim();
|
|
49208
|
-
const existingSession = Object.values(input.state.sessions).find((session3) => session3.transport_session === coordinatorSession);
|
|
49096
|
+
const existingSession = Object.values(input.state.sessions).find((session3) => stableCoordinatorSession(session3.transport_session) === stableCoordinatorSession(coordinatorSession));
|
|
49209
49097
|
const workspace3 = input.workspace?.trim();
|
|
49210
49098
|
if (workspace3) {
|
|
49211
49099
|
if (existingSession) {
|
|
@@ -49251,10 +49139,10 @@ function createMcpStdioIdentityResolver(input) {
|
|
|
49251
49139
|
const workspace3 = input.workspace?.trim() || null;
|
|
49252
49140
|
const sourceHandle = input.sourceHandle?.trim() || null;
|
|
49253
49141
|
const resolvedWorkspace = workspace3;
|
|
49254
|
-
const resolvedCoordinatorSession = parsedCoordinatorSession ?? inferExternalCoordinatorSession({
|
|
49142
|
+
const resolvedCoordinatorSession = stableCoordinatorSession(parsedCoordinatorSession ?? inferExternalCoordinatorSession({
|
|
49255
49143
|
clientName: context.clientName,
|
|
49256
49144
|
...resolvedWorkspace ? { workspace: resolvedWorkspace } : { instanceId }
|
|
49257
|
-
});
|
|
49145
|
+
}));
|
|
49258
49146
|
const startup = await prepareMcpCoordinatorStartup({
|
|
49259
49147
|
coordinatorSession: resolvedCoordinatorSession,
|
|
49260
49148
|
...resolvedWorkspace ? { workspace: resolvedWorkspace } : {},
|