workspacecord 1.1.2 → 1.1.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/{archive-manager-XM3UPOY2.js → archive-manager-RW36JGUV.js} +4 -4
- package/dist/{attachment-cli-IGQBB6YJ.js → attachment-cli-MF7XZ4WT.js} +2 -2
- package/dist/{chunk-GMYN4SYT.js → chunk-4KQ7OSK7.js} +3 -3
- package/dist/{chunk-ZAQV2RZS.js → chunk-7GTUWAQR.js} +341 -1158
- package/dist/{chunk-I6EOCCQV.js → chunk-AGB4GP4G.js} +918 -620
- package/dist/{chunk-L2ZJXV6H.js → chunk-BFINJJYL.js} +1 -1
- package/dist/{chunk-UEX7U2KW.js → chunk-IVXCJA5I.js} +902 -232
- package/dist/chunk-WON3DPE4.js +5092 -0
- package/dist/{chunk-COXPTYH5.js → chunk-WP6YJVAE.js} +4 -4
- package/dist/{chunk-54DP53ZK.js → chunk-ZO62NAYX.js} +29 -3
- package/dist/cli-framework-7E5MKPMM.js +18 -0
- package/dist/cli.js +9 -9
- package/dist/{codex-launcher-VDQ5VZPT.js → codex-launcher-ZBQ5VL6L.js} +1 -1
- package/dist/{codex-provider-NYI7KBGO.js → codex-provider-Q4Z6UKO6.js} +1 -1
- package/dist/{config-cli-RQR2ZRQ5.js → config-cli-7JEV3WYY.js} +2 -2
- package/dist/{panel-adapter-QTDL3S6O.js → panel-adapter-U75WXDLB.js} +4 -4
- package/dist/{project-cli-6P6ZWDR6.js → project-cli-ZXMHOFUJ.js} +2 -2
- package/dist/{project-registry-OEVPECMS.js → project-registry-ED6P5ZTM.js} +2 -2
- package/dist/{session-local-registration-RIO5EPZ5.js → session-local-registration-MISPPGXF.js} +3 -3
- package/dist/{setup-KOS7SRSL.js → setup-ZFVMMNT2.js} +1 -1
- package/package.json +1 -1
- package/dist/chunk-RK6EIZOL.js +0 -589
- package/dist/cli-framework-SQM2465A.js +0 -18
|
@@ -8,15 +8,15 @@ import {
|
|
|
8
8
|
cleanupSessionPanel,
|
|
9
9
|
deliver,
|
|
10
10
|
flushDigest,
|
|
11
|
-
gateCoordinator,
|
|
12
11
|
generatePerformanceReport,
|
|
13
12
|
getPendingAnswers,
|
|
14
13
|
getQuestionCount,
|
|
14
|
+
getSessionContext,
|
|
15
15
|
getSessionProjection,
|
|
16
|
+
getSessionView,
|
|
16
17
|
handleAwaitingHuman,
|
|
17
18
|
handleResultEvent,
|
|
18
19
|
initializeSessionPanel,
|
|
19
|
-
normalizeCodexEvent,
|
|
20
20
|
notifyUnmanagedCodexHint,
|
|
21
21
|
queueDigest,
|
|
22
22
|
registerExistingStatusCard,
|
|
@@ -27,10 +27,10 @@ import {
|
|
|
27
27
|
startPerformanceMonitoring,
|
|
28
28
|
stopPerformanceMonitoring,
|
|
29
29
|
updateSessionState
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-7GTUWAQR.js";
|
|
31
31
|
import {
|
|
32
32
|
registerMessageAttachments
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-BFINJJYL.js";
|
|
34
34
|
import {
|
|
35
35
|
addMcpServer,
|
|
36
36
|
addSkill,
|
|
@@ -51,14 +51,14 @@ import {
|
|
|
51
51
|
setControlChannelId,
|
|
52
52
|
setHistoryChannelId,
|
|
53
53
|
setPersonality
|
|
54
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-4KQ7OSK7.js";
|
|
55
55
|
import {
|
|
56
56
|
getAllRegisteredProjects
|
|
57
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-ZO62NAYX.js";
|
|
58
58
|
import {
|
|
59
59
|
buildClaudeSubagentProviderSessionId,
|
|
60
60
|
registerLocalSession
|
|
61
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-WP6YJVAE.js";
|
|
62
62
|
import {
|
|
63
63
|
abortSession,
|
|
64
64
|
abortSessionWithReason,
|
|
@@ -67,9 +67,9 @@ import {
|
|
|
67
67
|
createSession,
|
|
68
68
|
debouncedSaveSession,
|
|
69
69
|
endSession,
|
|
70
|
+
gateService,
|
|
70
71
|
getAllSessions,
|
|
71
72
|
getOutputPort,
|
|
72
|
-
getSession,
|
|
73
73
|
getSessionByChannel,
|
|
74
74
|
getSessionByProviderSession,
|
|
75
75
|
getSessionController,
|
|
@@ -78,6 +78,7 @@ import {
|
|
|
78
78
|
getSessionsByCategory,
|
|
79
79
|
loadSessions,
|
|
80
80
|
markSessionGenerating,
|
|
81
|
+
normalizeCodexEvent,
|
|
81
82
|
registerOutputPort,
|
|
82
83
|
resolveCodexSessionFromMonitor,
|
|
83
84
|
resolveEffectiveClaudePermissionMode,
|
|
@@ -91,21 +92,26 @@ import {
|
|
|
91
92
|
setSessionController,
|
|
92
93
|
setStatusCardBinding,
|
|
93
94
|
setVerbose,
|
|
95
|
+
stateMachine,
|
|
94
96
|
updateSession,
|
|
95
97
|
updateSessionPermissions,
|
|
96
98
|
updateWorkflowState
|
|
97
|
-
} from "./chunk-
|
|
99
|
+
} from "./chunk-WON3DPE4.js";
|
|
98
100
|
import {
|
|
101
|
+
JsonFileRepository,
|
|
102
|
+
MonitorRunEnded,
|
|
103
|
+
MonitorRunStarted,
|
|
99
104
|
ServiceBus,
|
|
100
105
|
config,
|
|
101
106
|
formatDuration,
|
|
102
107
|
formatRelative,
|
|
103
108
|
formatUptime,
|
|
109
|
+
getDomainBus,
|
|
104
110
|
intervalService,
|
|
105
111
|
isAbortError,
|
|
106
112
|
isUserAllowed,
|
|
107
113
|
truncate
|
|
108
|
-
} from "./chunk-
|
|
114
|
+
} from "./chunk-IVXCJA5I.js";
|
|
109
115
|
import {
|
|
110
116
|
__commonJS,
|
|
111
117
|
__require,
|
|
@@ -601,9 +607,9 @@ var require_cross_spawn = __commonJS({
|
|
|
601
607
|
}
|
|
602
608
|
function spawnSync2(command, args, options) {
|
|
603
609
|
const parsed = parse(command, args, options);
|
|
604
|
-
const
|
|
605
|
-
|
|
606
|
-
return
|
|
610
|
+
const result2 = cp.spawnSync(parsed.command, parsed.args, parsed.options);
|
|
611
|
+
result2.error = result2.error || enoent.verifyENOENTSync(result2.status, parsed);
|
|
612
|
+
return result2;
|
|
607
613
|
}
|
|
608
614
|
module.exports = spawn2;
|
|
609
615
|
module.exports.spawn = spawn2;
|
|
@@ -858,7 +864,7 @@ providers.set("claude", new ClaudeProvider());
|
|
|
858
864
|
var codexLoadAttempted = false;
|
|
859
865
|
async function loadCodexProvider() {
|
|
860
866
|
try {
|
|
861
|
-
const { CodexProvider } = await import("./codex-provider-
|
|
867
|
+
const { CodexProvider } = await import("./codex-provider-Q4Z6UKO6.js");
|
|
862
868
|
providers.set("codex", new CodexProvider());
|
|
863
869
|
codexLoadAttempted = true;
|
|
864
870
|
} catch (err) {
|
|
@@ -1033,34 +1039,29 @@ function buildProviderOptions(session, controller, isMonitor = false, runtimeOve
|
|
|
1033
1039
|
};
|
|
1034
1040
|
}
|
|
1035
1041
|
async function* sendPrompt(sessionId, prompt, runtimeOverrides = {}) {
|
|
1036
|
-
const
|
|
1037
|
-
if (!
|
|
1038
|
-
if (session.isGenerating) throw new Error("Session is already generating");
|
|
1042
|
+
const ctx = getSessionContext(sessionId);
|
|
1043
|
+
if (!ctx) throw new Error(`Session "${sessionId}" not found`);
|
|
1044
|
+
if (ctx.session.isGenerating) throw new Error("Session is already generating");
|
|
1039
1045
|
const controller = new AbortController();
|
|
1040
|
-
setSessionController(
|
|
1041
|
-
markSessionGenerating(
|
|
1042
|
-
const provider = await ensureProvider(session.provider);
|
|
1046
|
+
setSessionController(ctx.sessionId, controller);
|
|
1047
|
+
markSessionGenerating(ctx.sessionId, true);
|
|
1048
|
+
const provider = await ensureProvider(ctx.session.provider);
|
|
1043
1049
|
try {
|
|
1044
1050
|
const stream = provider.sendPrompt(
|
|
1045
1051
|
prompt,
|
|
1046
|
-
buildProviderOptions(session, controller, false, runtimeOverrides)
|
|
1052
|
+
buildProviderOptions(ctx.session, controller, false, runtimeOverrides)
|
|
1047
1053
|
);
|
|
1048
1054
|
for await (const event of stream) {
|
|
1049
1055
|
if (event.type === "session_init") {
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
current2.providerSessionId = event.providerSessionId || void 0;
|
|
1053
|
-
debouncedSaveSession();
|
|
1054
|
-
}
|
|
1056
|
+
ctx.session.providerSessionId = event.providerSessionId || void 0;
|
|
1057
|
+
ctx.save();
|
|
1055
1058
|
}
|
|
1056
1059
|
if (event.type === "result") {
|
|
1057
|
-
|
|
1058
|
-
if (current2) current2.totalCost += event.costUsd;
|
|
1060
|
+
ctx.session.totalCost += event.costUsd;
|
|
1059
1061
|
}
|
|
1060
1062
|
yield event;
|
|
1061
1063
|
}
|
|
1062
|
-
|
|
1063
|
-
if (current) current.messageCount++;
|
|
1064
|
+
ctx.session.messageCount++;
|
|
1064
1065
|
} catch (err) {
|
|
1065
1066
|
if (!isAbortError(err)) {
|
|
1066
1067
|
throw err;
|
|
@@ -1072,39 +1073,34 @@ async function* sendPrompt(sessionId, prompt, runtimeOverrides = {}) {
|
|
|
1072
1073
|
await saveSessionImmediate();
|
|
1073
1074
|
} catch (cleanupErr) {
|
|
1074
1075
|
console.error(`[ProviderRuntime] cleanup error for session ${sessionId}:`, cleanupErr);
|
|
1075
|
-
const
|
|
1076
|
-
if (
|
|
1076
|
+
const fallback = getSessionContext(sessionId);
|
|
1077
|
+
if (fallback) fallback.session.isGenerating = false;
|
|
1077
1078
|
}
|
|
1078
1079
|
}
|
|
1079
1080
|
}
|
|
1080
1081
|
async function* continueSessionWithOverrides(sessionId, runtimeOverrides = {}) {
|
|
1081
|
-
const
|
|
1082
|
-
if (!
|
|
1083
|
-
if (session.isGenerating) throw new Error("Session is already generating");
|
|
1082
|
+
const ctx = getSessionContext(sessionId);
|
|
1083
|
+
if (!ctx) throw new Error(`Session "${sessionId}" not found`);
|
|
1084
|
+
if (ctx.session.isGenerating) throw new Error("Session is already generating");
|
|
1084
1085
|
const controller = new AbortController();
|
|
1085
|
-
setSessionController(
|
|
1086
|
-
markSessionGenerating(
|
|
1087
|
-
const provider = await ensureProvider(session.provider);
|
|
1086
|
+
setSessionController(ctx.sessionId, controller);
|
|
1087
|
+
markSessionGenerating(ctx.sessionId, true);
|
|
1088
|
+
const provider = await ensureProvider(ctx.session.provider);
|
|
1088
1089
|
try {
|
|
1089
1090
|
const stream = provider.continueSession(
|
|
1090
|
-
buildProviderOptions(session, controller, false, runtimeOverrides)
|
|
1091
|
+
buildProviderOptions(ctx.session, controller, false, runtimeOverrides)
|
|
1091
1092
|
);
|
|
1092
1093
|
for await (const event of stream) {
|
|
1093
1094
|
if (event.type === "session_init") {
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
current2.providerSessionId = event.providerSessionId || void 0;
|
|
1097
|
-
debouncedSaveSession();
|
|
1098
|
-
}
|
|
1095
|
+
ctx.session.providerSessionId = event.providerSessionId || void 0;
|
|
1096
|
+
ctx.save();
|
|
1099
1097
|
}
|
|
1100
1098
|
if (event.type === "result") {
|
|
1101
|
-
|
|
1102
|
-
if (current2) current2.totalCost += event.costUsd;
|
|
1099
|
+
ctx.session.totalCost += event.costUsd;
|
|
1103
1100
|
}
|
|
1104
1101
|
yield event;
|
|
1105
1102
|
}
|
|
1106
|
-
|
|
1107
|
-
if (current) current.messageCount++;
|
|
1103
|
+
ctx.session.messageCount++;
|
|
1108
1104
|
} catch (err) {
|
|
1109
1105
|
if (!isAbortError(err)) {
|
|
1110
1106
|
throw err;
|
|
@@ -1116,39 +1112,33 @@ async function* continueSessionWithOverrides(sessionId, runtimeOverrides = {}) {
|
|
|
1116
1112
|
await saveSessionImmediate();
|
|
1117
1113
|
} catch (cleanupErr) {
|
|
1118
1114
|
console.error(`[ProviderRuntime] cleanup error for session ${sessionId}:`, cleanupErr);
|
|
1119
|
-
const
|
|
1120
|
-
if (
|
|
1115
|
+
const fallback = getSessionContext(sessionId);
|
|
1116
|
+
if (fallback) fallback.session.isGenerating = false;
|
|
1121
1117
|
}
|
|
1122
1118
|
}
|
|
1123
1119
|
}
|
|
1124
1120
|
async function* sendMonitorPrompt(sessionId, prompt) {
|
|
1125
|
-
const
|
|
1126
|
-
if (!
|
|
1127
|
-
const provider = await ensureProvider(session.provider);
|
|
1128
|
-
|
|
1129
|
-
if (current) current.lastActivity = Date.now();
|
|
1121
|
+
const ctx = getSessionContext(sessionId);
|
|
1122
|
+
if (!ctx) throw new Error(`Session "${sessionId}" not found`);
|
|
1123
|
+
const provider = await ensureProvider(ctx.session.provider);
|
|
1124
|
+
ctx.session.lastActivity = Date.now();
|
|
1130
1125
|
const mainController = getSessionController(sessionId);
|
|
1131
1126
|
const controller = new AbortController();
|
|
1132
1127
|
const onMainAbort = () => controller.abort();
|
|
1133
1128
|
mainController?.signal.addEventListener("abort", onMainAbort, { once: true });
|
|
1134
1129
|
try {
|
|
1135
|
-
const stream = provider.sendPrompt(prompt, buildProviderOptions(session, controller, true));
|
|
1130
|
+
const stream = provider.sendPrompt(prompt, buildProviderOptions(ctx.session, controller, true));
|
|
1136
1131
|
for await (const event of stream) {
|
|
1137
1132
|
if (event.type === "session_init") {
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
cur2.monitorProviderSessionId = event.providerSessionId || void 0;
|
|
1141
|
-
debouncedSaveSession();
|
|
1142
|
-
}
|
|
1133
|
+
ctx.session.monitorProviderSessionId = event.providerSessionId || void 0;
|
|
1134
|
+
ctx.save();
|
|
1143
1135
|
}
|
|
1144
1136
|
if (event.type === "result") {
|
|
1145
|
-
|
|
1146
|
-
if (cur2) cur2.totalCost += event.costUsd;
|
|
1137
|
+
ctx.session.totalCost += event.costUsd;
|
|
1147
1138
|
}
|
|
1148
1139
|
yield event;
|
|
1149
1140
|
}
|
|
1150
|
-
|
|
1151
|
-
if (cur) cur.lastActivity = Date.now();
|
|
1141
|
+
ctx.session.lastActivity = Date.now();
|
|
1152
1142
|
debouncedSaveSession();
|
|
1153
1143
|
} catch (err) {
|
|
1154
1144
|
if (!isAbortError(err)) {
|
|
@@ -1161,21 +1151,21 @@ async function* sendMonitorPrompt(sessionId, prompt) {
|
|
|
1161
1151
|
|
|
1162
1152
|
// ../engine/src/executor/permission-gate.ts
|
|
1163
1153
|
function refreshSession(session) {
|
|
1164
|
-
return
|
|
1154
|
+
return getSessionView(session.id) ?? session;
|
|
1165
1155
|
}
|
|
1166
1156
|
function waitForGateResolution(session, gateId) {
|
|
1167
1157
|
console.log(`[SessionExecutor] gate:waiting sessionId=${session.id} gateId=${gateId}`);
|
|
1168
1158
|
return new Promise((resolve2) => {
|
|
1169
1159
|
let settled = false;
|
|
1170
|
-
const settle = (
|
|
1160
|
+
const settle = (result2) => {
|
|
1171
1161
|
if (settled) return;
|
|
1172
1162
|
settled = true;
|
|
1173
1163
|
console.log(
|
|
1174
|
-
`[SessionExecutor] gate:resolved sessionId=${session.id} gateId=${gateId} action=${
|
|
1164
|
+
`[SessionExecutor] gate:resolved sessionId=${session.id} gateId=${gateId} action=${result2.action} source=${result2.source}`
|
|
1175
1165
|
);
|
|
1176
|
-
resolve2(
|
|
1166
|
+
resolve2(result2);
|
|
1177
1167
|
};
|
|
1178
|
-
|
|
1168
|
+
gateService.registerReceiptHandle(gateId, {
|
|
1179
1169
|
type: session.provider === "codex" ? "codex" : "claude",
|
|
1180
1170
|
sessionId: session.id,
|
|
1181
1171
|
resolve: (action, source) => settle({ action, source }),
|
|
@@ -1259,7 +1249,7 @@ function shouldUseClaudePermissionHandler(session) {
|
|
|
1259
1249
|
|
|
1260
1250
|
// ../engine/src/executor/session-hooks.ts
|
|
1261
1251
|
function refreshSession2(session) {
|
|
1262
|
-
return
|
|
1252
|
+
return getSessionView(session.id) ?? session;
|
|
1263
1253
|
}
|
|
1264
1254
|
function applyWorkflowHook(session, hook, patch = {}) {
|
|
1265
1255
|
return updateWorkflowState(session.id, (current) => ({
|
|
@@ -1309,30 +1299,30 @@ function extractRemainingGaps(text) {
|
|
|
1309
1299
|
(sentence) => /\b(still|missing|need|remaining|not yet|left to|have not)\b/i.test(sentence)
|
|
1310
1300
|
).slice(0, 5);
|
|
1311
1301
|
}
|
|
1312
|
-
function buildWorkerProgressReport(goal,
|
|
1313
|
-
const changedFiles =
|
|
1314
|
-
const recentCommands =
|
|
1302
|
+
function buildWorkerProgressReport(goal, result2) {
|
|
1303
|
+
const changedFiles = result2.changedFiles ?? [];
|
|
1304
|
+
const recentCommands = result2.recentCommands ?? [];
|
|
1315
1305
|
const validationCommands = recentCommands.filter(
|
|
1316
1306
|
(command) => /\b(test|vitest|jest|pytest|npm test|pnpm test|yarn test|grader|validate|check|lint)\b/i.test(
|
|
1317
1307
|
command
|
|
1318
1308
|
)
|
|
1319
1309
|
).slice(0, 10);
|
|
1320
|
-
const meaningfulExecution =
|
|
1321
|
-
const blockers =
|
|
1310
|
+
const meaningfulExecution = result2.commandCount > 0 || result2.fileChangeCount > 0;
|
|
1311
|
+
const blockers = result2.hadError ? ["The latest pass reported an error or stalled outcome."] : [];
|
|
1322
1312
|
return {
|
|
1323
1313
|
originalGoal: goal,
|
|
1324
|
-
textualResponse: summarizeWorkerText(
|
|
1325
|
-
commandCount:
|
|
1326
|
-
fileChangeCount:
|
|
1314
|
+
textualResponse: summarizeWorkerText(result2.text),
|
|
1315
|
+
commandCount: result2.commandCount,
|
|
1316
|
+
fileChangeCount: result2.fileChangeCount,
|
|
1327
1317
|
meaningfulExecutionEvidence: meaningfulExecution,
|
|
1328
|
-
providerReportedSuccess:
|
|
1329
|
-
workerErrorsObserved:
|
|
1330
|
-
askedForHumanInput:
|
|
1331
|
-
claimedCompletedOutcomes: extractClaimedCompletedOutcomes(
|
|
1318
|
+
providerReportedSuccess: result2.success === null ? "unknown" : result2.success ? "yes" : "no",
|
|
1319
|
+
workerErrorsObserved: result2.hadError,
|
|
1320
|
+
askedForHumanInput: result2.askedUser,
|
|
1321
|
+
claimedCompletedOutcomes: extractClaimedCompletedOutcomes(result2.text),
|
|
1332
1322
|
artifacts: changedFiles,
|
|
1333
1323
|
validationCommands,
|
|
1334
|
-
goalAssessment:
|
|
1335
|
-
remainingGaps: extractRemainingGaps(
|
|
1324
|
+
goalAssessment: result2.text.trim() ? truncate(result2.text.trim(), 1200) : meaningfulExecution ? "The worker executed commands or changed files but did not provide an explicit textual assessment." : "The worker did not provide a substantive assessment of progress toward the goal.",
|
|
1325
|
+
remainingGaps: extractRemainingGaps(result2.text),
|
|
1336
1326
|
blockers
|
|
1337
1327
|
};
|
|
1338
1328
|
}
|
|
@@ -1569,6 +1559,100 @@ function parseAskUserDecision(text) {
|
|
|
1569
1559
|
}
|
|
1570
1560
|
}
|
|
1571
1561
|
|
|
1562
|
+
// ../engine/src/executor/monitor-run-store.ts
|
|
1563
|
+
var monitorRepo = new JsonFileRepository({
|
|
1564
|
+
filename: "monitor-runs.json",
|
|
1565
|
+
idField: "id",
|
|
1566
|
+
debounceMs: 0
|
|
1567
|
+
});
|
|
1568
|
+
var initialized = false;
|
|
1569
|
+
async function ensureInit() {
|
|
1570
|
+
if (initialized) return;
|
|
1571
|
+
await monitorRepo.init();
|
|
1572
|
+
initialized = true;
|
|
1573
|
+
}
|
|
1574
|
+
function makeId(sessionId, startedAt) {
|
|
1575
|
+
const suffix = Math.random().toString(36).slice(2, 8);
|
|
1576
|
+
return `${sessionId}:${startedAt}:${suffix}`;
|
|
1577
|
+
}
|
|
1578
|
+
async function beginMonitorRun(params) {
|
|
1579
|
+
await ensureInit();
|
|
1580
|
+
const now = Date.now();
|
|
1581
|
+
const stale = monitorRepo.find({
|
|
1582
|
+
where: { sessionId: params.sessionId, status: "running" }
|
|
1583
|
+
});
|
|
1584
|
+
for (const old of stale) {
|
|
1585
|
+
await monitorRepo.update(old.id, { status: "abandoned", lastCheckpointAt: now });
|
|
1586
|
+
}
|
|
1587
|
+
const run = {
|
|
1588
|
+
id: makeId(params.sessionId, now),
|
|
1589
|
+
sessionId: params.sessionId,
|
|
1590
|
+
goal: params.goal,
|
|
1591
|
+
iteration: 0,
|
|
1592
|
+
maxIterations: params.maxIterations,
|
|
1593
|
+
status: "running",
|
|
1594
|
+
startedAt: now,
|
|
1595
|
+
lastCheckpointAt: now
|
|
1596
|
+
};
|
|
1597
|
+
await monitorRepo.save(run);
|
|
1598
|
+
getDomainBus().emit(
|
|
1599
|
+
MonitorRunStarted,
|
|
1600
|
+
{
|
|
1601
|
+
sessionId: run.sessionId,
|
|
1602
|
+
runId: run.id,
|
|
1603
|
+
goal: run.goal,
|
|
1604
|
+
maxIterations: run.maxIterations
|
|
1605
|
+
},
|
|
1606
|
+
"monitor-run-store"
|
|
1607
|
+
);
|
|
1608
|
+
return run;
|
|
1609
|
+
}
|
|
1610
|
+
async function checkpointMonitorRun(runId, patch) {
|
|
1611
|
+
await ensureInit();
|
|
1612
|
+
return monitorRepo.update(runId, { ...patch, lastCheckpointAt: Date.now() });
|
|
1613
|
+
}
|
|
1614
|
+
async function finishMonitorRun(runId, status, finalPatch = {}) {
|
|
1615
|
+
await ensureInit();
|
|
1616
|
+
const updated = await monitorRepo.update(runId, {
|
|
1617
|
+
...finalPatch,
|
|
1618
|
+
status,
|
|
1619
|
+
lastCheckpointAt: Date.now()
|
|
1620
|
+
});
|
|
1621
|
+
if (updated) {
|
|
1622
|
+
getDomainBus().emit(
|
|
1623
|
+
MonitorRunEnded,
|
|
1624
|
+
{
|
|
1625
|
+
sessionId: updated.sessionId,
|
|
1626
|
+
runId: updated.id,
|
|
1627
|
+
status,
|
|
1628
|
+
iteration: updated.iteration,
|
|
1629
|
+
rationale: updated.lastRationale
|
|
1630
|
+
},
|
|
1631
|
+
"monitor-run-store"
|
|
1632
|
+
);
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
async function reconcileMonitorRunsOnStartup() {
|
|
1636
|
+
await ensureInit();
|
|
1637
|
+
const running = monitorRepo.find({ where: { status: "running" } });
|
|
1638
|
+
const now = Date.now();
|
|
1639
|
+
for (const run of running) {
|
|
1640
|
+
await monitorRepo.update(run.id, { status: "abandoned", lastCheckpointAt: now });
|
|
1641
|
+
getDomainBus().emit(
|
|
1642
|
+
MonitorRunEnded,
|
|
1643
|
+
{
|
|
1644
|
+
sessionId: run.sessionId,
|
|
1645
|
+
runId: run.id,
|
|
1646
|
+
status: "abandoned",
|
|
1647
|
+
iteration: run.iteration,
|
|
1648
|
+
rationale: run.lastRationale
|
|
1649
|
+
},
|
|
1650
|
+
"monitor-run-store"
|
|
1651
|
+
);
|
|
1652
|
+
}
|
|
1653
|
+
return running;
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1572
1656
|
// ../engine/src/executor/monitor-loop.ts
|
|
1573
1657
|
var MAX_MONITOR_ITERATIONS = 6;
|
|
1574
1658
|
async function runMonitorDecision(session, goal, workerResult, iteration) {
|
|
@@ -1786,6 +1870,16 @@ async function runMonitorLoop(session, channel, goal, initialResult, runWorkerPa
|
|
|
1786
1870
|
console.log(
|
|
1787
1871
|
`[SessionExecutor] monitor:loop-start sessionId=${session.id} goal=${truncate(goal, 80)}`
|
|
1788
1872
|
);
|
|
1873
|
+
const monitorRun = await beginMonitorRun({
|
|
1874
|
+
sessionId: session.id,
|
|
1875
|
+
goal,
|
|
1876
|
+
maxIterations: MAX_MONITOR_ITERATIONS
|
|
1877
|
+
}).catch((err) => {
|
|
1878
|
+
console.warn(
|
|
1879
|
+
`[SessionExecutor] failed to persist MonitorRun for session ${session.id}: ${err.message}`
|
|
1880
|
+
);
|
|
1881
|
+
return null;
|
|
1882
|
+
});
|
|
1789
1883
|
let workerResult = initialResult;
|
|
1790
1884
|
let currentSession = refreshSession2(session);
|
|
1791
1885
|
for (let iteration = 1; iteration <= MAX_MONITOR_ITERATIONS; iteration++) {
|
|
@@ -1855,6 +1949,13 @@ async function runMonitorLoop(session, channel, goal, initialResult, runWorkerPa
|
|
|
1855
1949
|
});
|
|
1856
1950
|
const summary = decision.completionSummary || decision.rationale || "The monitor judged the request complete.";
|
|
1857
1951
|
await getOutputPort().handleResult(currentSession.id, createSyntheticResult(true, summary), summary);
|
|
1952
|
+
if (monitorRun) {
|
|
1953
|
+
await finishMonitorRun(monitorRun.id, "completed", {
|
|
1954
|
+
iteration,
|
|
1955
|
+
lastRationale: decision.rationale
|
|
1956
|
+
}).catch(() => {
|
|
1957
|
+
});
|
|
1958
|
+
}
|
|
1858
1959
|
console.log(
|
|
1859
1960
|
`[SessionExecutor] monitor:complete sessionId=${currentSession.id} iteration=${iteration} rationale=${truncate(decision.rationale, 80)}`
|
|
1860
1961
|
);
|
|
@@ -1875,11 +1976,26 @@ async function runMonitorLoop(session, channel, goal, initialResult, runWorkerPa
|
|
|
1875
1976
|
await getOutputPort().handleAwaitingHuman(currentSession.id, blocker, {
|
|
1876
1977
|
source: currentSession.provider === "codex" ? "codex" : "claude"
|
|
1877
1978
|
});
|
|
1979
|
+
if (monitorRun) {
|
|
1980
|
+
await finishMonitorRun(monitorRun.id, "blocked", {
|
|
1981
|
+
iteration,
|
|
1982
|
+
lastRationale: decision.rationale
|
|
1983
|
+
}).catch(() => {
|
|
1984
|
+
});
|
|
1985
|
+
}
|
|
1878
1986
|
console.warn(
|
|
1879
1987
|
`[SessionExecutor] monitor:blocked sessionId=${currentSession.id} iteration=${iteration} reason=${truncate(decision.rationale, 80)}`
|
|
1880
1988
|
);
|
|
1881
1989
|
return;
|
|
1882
1990
|
}
|
|
1991
|
+
if (monitorRun) {
|
|
1992
|
+
await checkpointMonitorRun(monitorRun.id, {
|
|
1993
|
+
iteration,
|
|
1994
|
+
lastRationale: decision.rationale,
|
|
1995
|
+
lastWorkerSummary: summarizeWorkerPass(buildWorkerProgressReport(goal, workerResult))
|
|
1996
|
+
}).catch(() => {
|
|
1997
|
+
});
|
|
1998
|
+
}
|
|
1883
1999
|
await updatePanelState(currentSession, "work_started", channel);
|
|
1884
2000
|
getOutputPort().queueDigest(currentSession.id, {
|
|
1885
2001
|
kind: "monitor",
|
|
@@ -1926,6 +2042,13 @@ async function runMonitorLoop(session, channel, goal, initialResult, runWorkerPa
|
|
|
1926
2042
|
await getOutputPort().handleAwaitingHuman(currentSession.id, limitSummary, {
|
|
1927
2043
|
source: currentSession.provider === "codex" ? "codex" : "claude"
|
|
1928
2044
|
});
|
|
2045
|
+
if (monitorRun) {
|
|
2046
|
+
await finishMonitorRun(monitorRun.id, "failed", {
|
|
2047
|
+
iteration: MAX_MONITOR_ITERATIONS,
|
|
2048
|
+
lastRationale: "Reached the continuation safety limit."
|
|
2049
|
+
}).catch(() => {
|
|
2050
|
+
});
|
|
2051
|
+
}
|
|
1929
2052
|
console.warn(
|
|
1930
2053
|
`[SessionExecutor] monitor:limit-reached sessionId=${currentSession.id} iterations=${MAX_MONITOR_ITERATIONS}`
|
|
1931
2054
|
);
|
|
@@ -1968,7 +2091,7 @@ async function runWorkerPass(session, channel, prompt, iteration, mode = "prompt
|
|
|
1968
2091
|
watchdogTimer = setTimeout(scheduleWatchdog, delay);
|
|
1969
2092
|
};
|
|
1970
2093
|
watchdogTimer = setTimeout(scheduleWatchdog, WATCHDOG_SLOW_INTERVAL);
|
|
1971
|
-
const
|
|
2094
|
+
const result2 = await getOutputPort().handleOutputStream(
|
|
1972
2095
|
stream,
|
|
1973
2096
|
channel,
|
|
1974
2097
|
session.id,
|
|
@@ -1984,10 +2107,10 @@ async function runWorkerPass(session, channel, prompt, iteration, mode = "prompt
|
|
|
1984
2107
|
const abortReason = consumeAbortReason(session.id);
|
|
1985
2108
|
if (watchdogTriggered || abortReason === "watchdog") {
|
|
1986
2109
|
const stalledResult = {
|
|
1987
|
-
...
|
|
2110
|
+
...result2,
|
|
1988
2111
|
hadError: true,
|
|
1989
2112
|
abortReason,
|
|
1990
|
-
text: annotateInactivityAbort(
|
|
2113
|
+
text: annotateInactivityAbort(result2.text, WORKER_IDLE_TIMEOUT_MS)
|
|
1991
2114
|
};
|
|
1992
2115
|
const stalledReport = buildWorkerProgressReport("", stalledResult);
|
|
1993
2116
|
applyWorkflowHook(session, "on_stall", {
|
|
@@ -2000,17 +2123,17 @@ async function runWorkerPass(session, channel, prompt, iteration, mode = "prompt
|
|
|
2000
2123
|
);
|
|
2001
2124
|
return stalledResult;
|
|
2002
2125
|
}
|
|
2003
|
-
const resultReport = buildWorkerProgressReport("",
|
|
2126
|
+
const resultReport = buildWorkerProgressReport("", result2);
|
|
2004
2127
|
applyWorkflowHook(session, "after_worker_pass", {
|
|
2005
2128
|
status: session.mode === "monitor" ? "monitor_review" : "idle",
|
|
2006
2129
|
lastWorkerSummary: summarizeWorkerPass(resultReport),
|
|
2007
2130
|
lastWorkerReport: resultReport
|
|
2008
2131
|
});
|
|
2009
2132
|
console.log(
|
|
2010
|
-
`[SessionExecutor] worker:end sessionId=${session.id} iteration=${iteration} commands=${
|
|
2133
|
+
`[SessionExecutor] worker:end sessionId=${session.id} iteration=${iteration} commands=${result2.commandCount} files=${result2.fileChangeCount} success=${result2.success} hasError=${result2.hadError}`
|
|
2011
2134
|
);
|
|
2012
2135
|
return {
|
|
2013
|
-
...
|
|
2136
|
+
...result2,
|
|
2014
2137
|
abortReason
|
|
2015
2138
|
};
|
|
2016
2139
|
} finally {
|
|
@@ -2031,7 +2154,7 @@ async function executeSessionPrompt(session, channel, prompt, options = {}) {
|
|
|
2031
2154
|
}
|
|
2032
2155
|
if ((options.updateMonitorGoal ?? true) && goalText && !session.monitorGoal) {
|
|
2033
2156
|
setMonitorGoal(session.id, goalText);
|
|
2034
|
-
session =
|
|
2157
|
+
session = getSessionView(session.id) ?? session;
|
|
2035
2158
|
}
|
|
2036
2159
|
const goal = session.monitorGoal || goalText;
|
|
2037
2160
|
if (!goal) {
|
|
@@ -2141,11 +2264,163 @@ function getExpandableContent(id) {
|
|
|
2141
2264
|
return expandableStore.get(id)?.content;
|
|
2142
2265
|
}
|
|
2143
2266
|
|
|
2144
|
-
// ../
|
|
2145
|
-
|
|
2267
|
+
// ../engine/src/executor/monitor-autoresume.ts
|
|
2268
|
+
async function reconcileAndCollectAutoResumeCandidates(policy) {
|
|
2269
|
+
const abandoned = await reconcileMonitorRunsOnStartup();
|
|
2270
|
+
if (policy === "abandon-only" || abandoned.length === 0) {
|
|
2271
|
+
return { abandoned, candidates: [] };
|
|
2272
|
+
}
|
|
2273
|
+
const candidates = [];
|
|
2274
|
+
for (const run of abandoned) {
|
|
2275
|
+
const session = getSessionView(run.sessionId);
|
|
2276
|
+
if (!session) continue;
|
|
2277
|
+
if (session.mode !== "monitor") continue;
|
|
2278
|
+
if (session.isGenerating) continue;
|
|
2279
|
+
const goal = session.monitorGoal || run.goal;
|
|
2280
|
+
if (!goal) continue;
|
|
2281
|
+
candidates.push({
|
|
2282
|
+
sessionId: session.id,
|
|
2283
|
+
channelId: session.channelId,
|
|
2284
|
+
runId: run.id,
|
|
2285
|
+
goal,
|
|
2286
|
+
lastIteration: run.iteration,
|
|
2287
|
+
lastRationale: run.lastRationale,
|
|
2288
|
+
abandonedRun: run
|
|
2289
|
+
});
|
|
2290
|
+
}
|
|
2291
|
+
return { abandoned, candidates };
|
|
2292
|
+
}
|
|
2146
2293
|
|
|
2147
|
-
// ../bot/src/
|
|
2148
|
-
|
|
2294
|
+
// ../bot/src/output/message-streamer.ts
|
|
2295
|
+
function detectRepetition(text) {
|
|
2296
|
+
const sentences = text.split(/[。!?\n]+/).filter((s) => s.trim().length > 5);
|
|
2297
|
+
if (sentences.length < 3) return { isRepetitive: false, cleanedText: text };
|
|
2298
|
+
const counts = /* @__PURE__ */ new Map();
|
|
2299
|
+
for (const sentence of sentences) {
|
|
2300
|
+
const normalized = sentence.trim();
|
|
2301
|
+
counts.set(normalized, (counts.get(normalized) || 0) + 1);
|
|
2302
|
+
}
|
|
2303
|
+
let maxCount = 0;
|
|
2304
|
+
let mostRepeated = "";
|
|
2305
|
+
for (const [sentence, count2] of counts) {
|
|
2306
|
+
if (count2 > maxCount) {
|
|
2307
|
+
maxCount = count2;
|
|
2308
|
+
mostRepeated = sentence;
|
|
2309
|
+
}
|
|
2310
|
+
}
|
|
2311
|
+
if (maxCount >= 5) {
|
|
2312
|
+
const parts = text.split(mostRepeated);
|
|
2313
|
+
const cleaned = parts.slice(0, 3).join(mostRepeated);
|
|
2314
|
+
return {
|
|
2315
|
+
isRepetitive: true,
|
|
2316
|
+
cleanedText: cleaned + `
|
|
2317
|
+
|
|
2318
|
+
\u26A0\uFE0F *[\u68C0\u6D4B\u5230\u91CD\u590D\u8F93\u51FA,\u5DF2\u622A\u65AD ${maxCount - 2} \u6B21\u91CD\u590D]*`
|
|
2319
|
+
};
|
|
2320
|
+
}
|
|
2321
|
+
return { isRepetitive: false, cleanedText: text };
|
|
2322
|
+
}
|
|
2323
|
+
var MessageStreamer = class {
|
|
2324
|
+
_channel;
|
|
2325
|
+
_sessionId;
|
|
2326
|
+
currentText = "";
|
|
2327
|
+
transcriptText = "";
|
|
2328
|
+
dirty = false;
|
|
2329
|
+
flushing = false;
|
|
2330
|
+
timer = null;
|
|
2331
|
+
INTERVAL = 400;
|
|
2332
|
+
constructor(channel, sessionId) {
|
|
2333
|
+
this._channel = channel;
|
|
2334
|
+
this._sessionId = sessionId;
|
|
2335
|
+
}
|
|
2336
|
+
append(text, options = {}) {
|
|
2337
|
+
this.currentText += text;
|
|
2338
|
+
if (options.persist !== false) {
|
|
2339
|
+
this.transcriptText += text;
|
|
2340
|
+
}
|
|
2341
|
+
this.dirty = true;
|
|
2342
|
+
this.scheduleFlush();
|
|
2343
|
+
}
|
|
2344
|
+
scheduleFlush() {
|
|
2345
|
+
if (this.timer || this.flushing) return;
|
|
2346
|
+
this.timer = setTimeout(() => {
|
|
2347
|
+
this.timer = null;
|
|
2348
|
+
this.flush().catch((err) => {
|
|
2349
|
+
console.error(`[MessageStreamer] flush error (session ${this._sessionId}):`, err);
|
|
2350
|
+
});
|
|
2351
|
+
}, this.INTERVAL);
|
|
2352
|
+
}
|
|
2353
|
+
async flush() {
|
|
2354
|
+
if (this.flushing || !this.dirty) return;
|
|
2355
|
+
this.flushing = true;
|
|
2356
|
+
try {
|
|
2357
|
+
this.dirty = false;
|
|
2358
|
+
if (this.currentText.trim()) {
|
|
2359
|
+
const plan = buildDeliveryPlan({
|
|
2360
|
+
sessionId: this._sessionId,
|
|
2361
|
+
chatId: this._channel.id,
|
|
2362
|
+
text: this.currentText,
|
|
2363
|
+
files: [],
|
|
2364
|
+
mode: "progress_update",
|
|
2365
|
+
policy: {
|
|
2366
|
+
textChunkLimit: config.textChunkLimit,
|
|
2367
|
+
chunkMode: config.chunkMode,
|
|
2368
|
+
replyToMode: config.replyToMode,
|
|
2369
|
+
ackReaction: config.ackReaction
|
|
2370
|
+
}
|
|
2371
|
+
});
|
|
2372
|
+
await deliver(this._channel, plan);
|
|
2373
|
+
}
|
|
2374
|
+
} finally {
|
|
2375
|
+
this.flushing = false;
|
|
2376
|
+
if (this.dirty) this.scheduleFlush();
|
|
2377
|
+
}
|
|
2378
|
+
}
|
|
2379
|
+
async waitForFlush() {
|
|
2380
|
+
const deadline = Date.now() + 1e4;
|
|
2381
|
+
while (this.flushing) {
|
|
2382
|
+
if (Date.now() > deadline) {
|
|
2383
|
+
console.warn(`[MessageStreamer] flush wait timeout (session ${this._sessionId}), forcing reset`);
|
|
2384
|
+
this.flushing = false;
|
|
2385
|
+
break;
|
|
2386
|
+
}
|
|
2387
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
2388
|
+
}
|
|
2389
|
+
}
|
|
2390
|
+
async finalize() {
|
|
2391
|
+
if (this.timer) {
|
|
2392
|
+
clearTimeout(this.timer);
|
|
2393
|
+
this.timer = null;
|
|
2394
|
+
}
|
|
2395
|
+
await this.waitForFlush();
|
|
2396
|
+
if (this.dirty) {
|
|
2397
|
+
this.dirty = false;
|
|
2398
|
+
const { cleanedText } = detectRepetition(this.currentText);
|
|
2399
|
+
this.currentText = cleanedText;
|
|
2400
|
+
}
|
|
2401
|
+
}
|
|
2402
|
+
async discard() {
|
|
2403
|
+
if (this.timer) {
|
|
2404
|
+
clearTimeout(this.timer);
|
|
2405
|
+
this.timer = null;
|
|
2406
|
+
}
|
|
2407
|
+
await this.waitForFlush();
|
|
2408
|
+
this.currentText = "";
|
|
2409
|
+
this.dirty = false;
|
|
2410
|
+
}
|
|
2411
|
+
getText() {
|
|
2412
|
+
return this.transcriptText;
|
|
2413
|
+
}
|
|
2414
|
+
destroy() {
|
|
2415
|
+
if (this.timer) {
|
|
2416
|
+
clearTimeout(this.timer);
|
|
2417
|
+
this.timer = null;
|
|
2418
|
+
}
|
|
2419
|
+
}
|
|
2420
|
+
};
|
|
2421
|
+
|
|
2422
|
+
// ../bot/src/output/event-handlers.ts
|
|
2423
|
+
import { existsSync } from "fs";
|
|
2149
2424
|
|
|
2150
2425
|
// ../bot/src/subagent-manager.ts
|
|
2151
2426
|
import {
|
|
@@ -2303,133 +2578,8 @@ function getSubagentSessions() {
|
|
|
2303
2578
|
return getAllSessions().filter((s) => s.type === "subagent");
|
|
2304
2579
|
}
|
|
2305
2580
|
|
|
2306
|
-
// ../bot/src/
|
|
2307
|
-
|
|
2308
|
-
const sentences = text.split(/[。!?\n]+/).filter((s) => s.trim().length > 5);
|
|
2309
|
-
if (sentences.length < 3) return { isRepetitive: false, cleanedText: text };
|
|
2310
|
-
const counts = /* @__PURE__ */ new Map();
|
|
2311
|
-
for (const sentence of sentences) {
|
|
2312
|
-
const normalized = sentence.trim();
|
|
2313
|
-
counts.set(normalized, (counts.get(normalized) || 0) + 1);
|
|
2314
|
-
}
|
|
2315
|
-
let maxCount = 0;
|
|
2316
|
-
let mostRepeated = "";
|
|
2317
|
-
for (const [sentence, count2] of counts) {
|
|
2318
|
-
if (count2 > maxCount) {
|
|
2319
|
-
maxCount = count2;
|
|
2320
|
-
mostRepeated = sentence;
|
|
2321
|
-
}
|
|
2322
|
-
}
|
|
2323
|
-
if (maxCount >= 5) {
|
|
2324
|
-
const parts = text.split(mostRepeated);
|
|
2325
|
-
const cleaned = parts.slice(0, 3).join(mostRepeated);
|
|
2326
|
-
return {
|
|
2327
|
-
isRepetitive: true,
|
|
2328
|
-
cleanedText: cleaned + `
|
|
2329
|
-
|
|
2330
|
-
\u26A0\uFE0F *[\u68C0\u6D4B\u5230\u91CD\u590D\u8F93\u51FA,\u5DF2\u622A\u65AD ${maxCount - 2} \u6B21\u91CD\u590D]*`
|
|
2331
|
-
};
|
|
2332
|
-
}
|
|
2333
|
-
return { isRepetitive: false, cleanedText: text };
|
|
2334
|
-
}
|
|
2335
|
-
var MessageStreamer = class {
|
|
2336
|
-
_channel;
|
|
2337
|
-
_sessionId;
|
|
2338
|
-
currentText = "";
|
|
2339
|
-
transcriptText = "";
|
|
2340
|
-
dirty = false;
|
|
2341
|
-
flushing = false;
|
|
2342
|
-
timer = null;
|
|
2343
|
-
INTERVAL = 400;
|
|
2344
|
-
constructor(channel, sessionId) {
|
|
2345
|
-
this._channel = channel;
|
|
2346
|
-
this._sessionId = sessionId;
|
|
2347
|
-
}
|
|
2348
|
-
append(text, options = {}) {
|
|
2349
|
-
this.currentText += text;
|
|
2350
|
-
if (options.persist !== false) {
|
|
2351
|
-
this.transcriptText += text;
|
|
2352
|
-
}
|
|
2353
|
-
this.dirty = true;
|
|
2354
|
-
this.scheduleFlush();
|
|
2355
|
-
}
|
|
2356
|
-
scheduleFlush() {
|
|
2357
|
-
if (this.timer || this.flushing) return;
|
|
2358
|
-
this.timer = setTimeout(() => {
|
|
2359
|
-
this.timer = null;
|
|
2360
|
-
this.flush().catch((err) => {
|
|
2361
|
-
console.error(`[MessageStreamer] flush error (session ${this._sessionId}):`, err);
|
|
2362
|
-
});
|
|
2363
|
-
}, this.INTERVAL);
|
|
2364
|
-
}
|
|
2365
|
-
async flush() {
|
|
2366
|
-
if (this.flushing || !this.dirty) return;
|
|
2367
|
-
this.flushing = true;
|
|
2368
|
-
try {
|
|
2369
|
-
this.dirty = false;
|
|
2370
|
-
if (this.currentText.trim()) {
|
|
2371
|
-
const plan = buildDeliveryPlan({
|
|
2372
|
-
sessionId: this._sessionId,
|
|
2373
|
-
chatId: this._channel.id,
|
|
2374
|
-
text: this.currentText,
|
|
2375
|
-
files: [],
|
|
2376
|
-
mode: "progress_update",
|
|
2377
|
-
policy: {
|
|
2378
|
-
textChunkLimit: config.textChunkLimit,
|
|
2379
|
-
chunkMode: config.chunkMode,
|
|
2380
|
-
replyToMode: config.replyToMode,
|
|
2381
|
-
ackReaction: config.ackReaction
|
|
2382
|
-
}
|
|
2383
|
-
});
|
|
2384
|
-
await deliver(this._channel, plan);
|
|
2385
|
-
}
|
|
2386
|
-
} finally {
|
|
2387
|
-
this.flushing = false;
|
|
2388
|
-
if (this.dirty) this.scheduleFlush();
|
|
2389
|
-
}
|
|
2390
|
-
}
|
|
2391
|
-
async waitForFlush() {
|
|
2392
|
-
const deadline = Date.now() + 1e4;
|
|
2393
|
-
while (this.flushing) {
|
|
2394
|
-
if (Date.now() > deadline) {
|
|
2395
|
-
console.warn(`[MessageStreamer] flush wait timeout (session ${this._sessionId}), forcing reset`);
|
|
2396
|
-
this.flushing = false;
|
|
2397
|
-
break;
|
|
2398
|
-
}
|
|
2399
|
-
await new Promise((r) => setTimeout(r, 50));
|
|
2400
|
-
}
|
|
2401
|
-
}
|
|
2402
|
-
async finalize() {
|
|
2403
|
-
if (this.timer) {
|
|
2404
|
-
clearTimeout(this.timer);
|
|
2405
|
-
this.timer = null;
|
|
2406
|
-
}
|
|
2407
|
-
await this.waitForFlush();
|
|
2408
|
-
if (this.dirty) {
|
|
2409
|
-
this.dirty = false;
|
|
2410
|
-
const { cleanedText } = detectRepetition(this.currentText);
|
|
2411
|
-
this.currentText = cleanedText;
|
|
2412
|
-
}
|
|
2413
|
-
}
|
|
2414
|
-
async discard() {
|
|
2415
|
-
if (this.timer) {
|
|
2416
|
-
clearTimeout(this.timer);
|
|
2417
|
-
this.timer = null;
|
|
2418
|
-
}
|
|
2419
|
-
await this.waitForFlush();
|
|
2420
|
-
this.currentText = "";
|
|
2421
|
-
this.dirty = false;
|
|
2422
|
-
}
|
|
2423
|
-
getText() {
|
|
2424
|
-
return this.transcriptText;
|
|
2425
|
-
}
|
|
2426
|
-
destroy() {
|
|
2427
|
-
if (this.timer) {
|
|
2428
|
-
clearTimeout(this.timer);
|
|
2429
|
-
this.timer = null;
|
|
2430
|
-
}
|
|
2431
|
-
}
|
|
2432
|
-
};
|
|
2581
|
+
// ../bot/src/codex-renderer.ts
|
|
2582
|
+
import { EmbedBuilder } from "discord.js";
|
|
2433
2583
|
|
|
2434
2584
|
// ../bot/src/output/interaction-controls.ts
|
|
2435
2585
|
import {
|
|
@@ -2474,24 +2624,267 @@ function shouldSuppressCommandExecution(command) {
|
|
|
2474
2624
|
return command.toLowerCase().includes("total-recall");
|
|
2475
2625
|
}
|
|
2476
2626
|
|
|
2627
|
+
// ../bot/src/output/event-handlers.ts
|
|
2628
|
+
function providerSource(sessionId) {
|
|
2629
|
+
const session = getSessionView(sessionId);
|
|
2630
|
+
return session?.provider === "codex" ? "codex" : "claude";
|
|
2631
|
+
}
|
|
2632
|
+
var textDelta = (event, ctx) => {
|
|
2633
|
+
ctx.streamer.append(event.text);
|
|
2634
|
+
};
|
|
2635
|
+
var askUser = async (event, ctx) => {
|
|
2636
|
+
ctx.state.askedUser = true;
|
|
2637
|
+
ctx.state.askUserQuestionsJson = event.questionsJson;
|
|
2638
|
+
await ctx.streamer.discard();
|
|
2639
|
+
const session = getSessionView(ctx.sessionId);
|
|
2640
|
+
if (!session) return;
|
|
2641
|
+
const source = providerSource(ctx.sessionId);
|
|
2642
|
+
await updateSessionState(ctx.sessionId, {
|
|
2643
|
+
type: "awaiting_human",
|
|
2644
|
+
sessionId: ctx.sessionId,
|
|
2645
|
+
source,
|
|
2646
|
+
confidence: "high",
|
|
2647
|
+
timestamp: Date.now(),
|
|
2648
|
+
metadata: { detail: event.questionsJson }
|
|
2649
|
+
});
|
|
2650
|
+
await flushDigest(ctx.sessionId);
|
|
2651
|
+
await handleAwaitingHuman(ctx.sessionId, event.questionsJson, { source });
|
|
2652
|
+
};
|
|
2653
|
+
var task = async (event, ctx) => {
|
|
2654
|
+
await ctx.streamer.finalize();
|
|
2655
|
+
queueDigest(ctx.sessionId, { kind: "tool", text: `\u4EFB\u52A1\u5DE5\u5177\uFF1A${event.action}` });
|
|
2656
|
+
ctx.state.lastToolName = event.action;
|
|
2657
|
+
};
|
|
2658
|
+
var taskStarted = async (event, ctx) => {
|
|
2659
|
+
await ctx.streamer.finalize();
|
|
2660
|
+
queueDigest(ctx.sessionId, {
|
|
2661
|
+
kind: "subagent",
|
|
2662
|
+
text: `\u5B50\u4EE3\u7406\u542F\u52A8\uFF1A${truncate(event.description, 80)}`
|
|
2663
|
+
});
|
|
2664
|
+
const session = getSessionView(ctx.sessionId);
|
|
2665
|
+
if (!session || ctx.channel.type === void 0) return;
|
|
2666
|
+
autoSpawnSubagentThread(session, event.taskId, event.description, ctx.channel).then((result2) => {
|
|
2667
|
+
if (result2) ctx.state.taskThreadMap.set(event.taskId, result2.threadId);
|
|
2668
|
+
}).catch(
|
|
2669
|
+
(err) => console.warn(
|
|
2670
|
+
`[OutputHandler] Failed to auto-spawn thread for task ${event.taskId}: ${err.message}`
|
|
2671
|
+
)
|
|
2672
|
+
);
|
|
2673
|
+
};
|
|
2674
|
+
var taskProgress = (event, ctx) => {
|
|
2675
|
+
if (event.summary) {
|
|
2676
|
+
queueDigest(ctx.sessionId, {
|
|
2677
|
+
kind: "subagent",
|
|
2678
|
+
text: `\u5B50\u4EE3\u7406\u8FDB\u5C55\uFF1A${truncate(event.summary, 100)}`
|
|
2679
|
+
});
|
|
2680
|
+
}
|
|
2681
|
+
const threadId = ctx.state.taskThreadMap.get(event.taskId);
|
|
2682
|
+
if (!threadId || !event.summary) return;
|
|
2683
|
+
const thread = ctx.channel.threads?.cache.get(threadId);
|
|
2684
|
+
if (!thread) return;
|
|
2685
|
+
thread.send(`\u{1F4DD} ${truncate(event.summary, 1900)}`).catch(
|
|
2686
|
+
(e) => console.warn(
|
|
2687
|
+
`[OutputHandler] Failed to send progress to thread: ${e.message}`
|
|
2688
|
+
)
|
|
2689
|
+
);
|
|
2690
|
+
};
|
|
2691
|
+
var taskDone = async (event, ctx) => {
|
|
2692
|
+
await ctx.streamer.finalize();
|
|
2693
|
+
queueDigest(ctx.sessionId, {
|
|
2694
|
+
kind: "subagent",
|
|
2695
|
+
text: `\u5B50\u4EE3\u7406${event.status === "completed" ? "\u5B8C\u6210" : "\u7ED3\u675F"}\uFF1A${truncate(event.summary || "No summary.", 100)}`
|
|
2696
|
+
});
|
|
2697
|
+
const threadId = ctx.state.taskThreadMap.get(event.taskId);
|
|
2698
|
+
if (!threadId) return;
|
|
2699
|
+
const thread = ctx.channel.threads?.cache.get(threadId);
|
|
2700
|
+
if (thread) {
|
|
2701
|
+
const emoji = event.status === "completed" ? "\u2705" : "\u274C";
|
|
2702
|
+
thread.send(`${emoji} \u5B50\u4EFB\u52A1${event.status === "completed" ? "\u5B8C\u6210" : "\u7ED3\u675F"}\uFF1A${truncate(event.summary || "", 1900)}`).catch(
|
|
2703
|
+
(e) => console.warn(
|
|
2704
|
+
`[OutputHandler] Failed to send task done to thread: ${e.message}`
|
|
2705
|
+
)
|
|
2706
|
+
);
|
|
2707
|
+
}
|
|
2708
|
+
ctx.state.taskThreadMap.delete(event.taskId);
|
|
2709
|
+
};
|
|
2710
|
+
var webSearch = (event, ctx) => {
|
|
2711
|
+
if (ctx.verbose) {
|
|
2712
|
+
queueDigest(ctx.sessionId, { kind: "search", text: `\u68C0\u7D22\uFF1A${truncate(event.query, 80)}` });
|
|
2713
|
+
}
|
|
2714
|
+
};
|
|
2715
|
+
var toolStart = async (event, ctx) => {
|
|
2716
|
+
await ctx.streamer.finalize();
|
|
2717
|
+
queueDigest(ctx.sessionId, { kind: "tool", text: `\u5DE5\u5177\uFF1A${event.toolName}` });
|
|
2718
|
+
ctx.state.lastToolName = event.toolName;
|
|
2719
|
+
};
|
|
2720
|
+
var toolResult = async (event, ctx) => {
|
|
2721
|
+
await ctx.streamer.finalize();
|
|
2722
|
+
if (ctx.verbose && event.result) {
|
|
2723
|
+
queueDigest(ctx.sessionId, {
|
|
2724
|
+
kind: "tool",
|
|
2725
|
+
text: `\u5DE5\u5177\u7ED3\u679C\uFF1A${truncate(ctx.state.lastToolName || event.toolName || "tool", 60)}`
|
|
2726
|
+
});
|
|
2727
|
+
}
|
|
2728
|
+
};
|
|
2729
|
+
var imageFile = (event, ctx) => {
|
|
2730
|
+
if (existsSync(event.filePath)) {
|
|
2731
|
+
ctx.state.pendingAttachments.push(event.filePath);
|
|
2732
|
+
}
|
|
2733
|
+
};
|
|
2734
|
+
var commandExecution = (event, ctx) => {
|
|
2735
|
+
ctx.state.commandCount++;
|
|
2736
|
+
if (ctx.state.recentCommands.length < 8) ctx.state.recentCommands.push(event.command);
|
|
2737
|
+
if (!shouldSuppressCommandExecution(event.command)) {
|
|
2738
|
+
queueDigest(ctx.sessionId, {
|
|
2739
|
+
kind: "command",
|
|
2740
|
+
text: `\u547D\u4EE4\uFF1A${truncate(event.command, 80)}${event.exitCode !== null ? `\uFF08\u9000\u51FA\u7801 ${event.exitCode}\uFF09` : ""}`
|
|
2741
|
+
});
|
|
2742
|
+
}
|
|
2743
|
+
};
|
|
2744
|
+
var fileChange = (event, ctx) => {
|
|
2745
|
+
ctx.state.fileChangeCount += event.changes.length;
|
|
2746
|
+
for (const change of event.changes) {
|
|
2747
|
+
if (!change.filePath) continue;
|
|
2748
|
+
if (ctx.state.changedFiles.includes(change.filePath)) continue;
|
|
2749
|
+
if (ctx.state.changedFiles.length >= 12) break;
|
|
2750
|
+
ctx.state.changedFiles.push(change.filePath);
|
|
2751
|
+
}
|
|
2752
|
+
queueDigest(ctx.sessionId, {
|
|
2753
|
+
kind: "file",
|
|
2754
|
+
text: `\u6587\u4EF6\u53D8\u66F4\uFF1A${event.changes.length} \u4E2A\uFF08\u6700\u8FD1\uFF1A${truncate(ctx.state.changedFiles.slice(-3).join(", "), 120)}\uFF09`
|
|
2755
|
+
});
|
|
2756
|
+
};
|
|
2757
|
+
var reasoning = (event, ctx) => {
|
|
2758
|
+
if (ctx.verbose) {
|
|
2759
|
+
queueDigest(ctx.sessionId, { kind: "reasoning", text: `\u63A8\u7406\uFF1A${truncate(event.text, 100)}` });
|
|
2760
|
+
}
|
|
2761
|
+
};
|
|
2762
|
+
var todoList = (event, ctx) => {
|
|
2763
|
+
const completed = event.items.filter((item) => item.completed).length;
|
|
2764
|
+
queueDigest(ctx.sessionId, {
|
|
2765
|
+
kind: "todo",
|
|
2766
|
+
text: `\u5F85\u529E\u66F4\u65B0\uFF1A${completed}/${event.items.length} \u5DF2\u5B8C\u6210`
|
|
2767
|
+
});
|
|
2768
|
+
};
|
|
2769
|
+
var MODE_LABELS = {
|
|
2770
|
+
auto: "\u81EA\u52A8",
|
|
2771
|
+
plan: "\u8BA1\u5212",
|
|
2772
|
+
normal: "\u666E\u901A",
|
|
2773
|
+
monitor: "\u76D1\u63A7"
|
|
2774
|
+
};
|
|
2775
|
+
var result = async (event, ctx) => {
|
|
2776
|
+
ctx.state.success = event.success;
|
|
2777
|
+
const lastText = ctx.streamer.getText();
|
|
2778
|
+
const cost = event.costUsd.toFixed(4);
|
|
2779
|
+
const duration = event.durationMs ? `${(event.durationMs / 1e3).toFixed(1)}s` : "unknown";
|
|
2780
|
+
const turns = event.numTurns || 0;
|
|
2781
|
+
const modeLabel = MODE_LABELS[ctx.mode] || "\u81EA\u52A8";
|
|
2782
|
+
const statusLine = event.success ? `-# $${cost} | ${duration} | ${turns} turns | ${modeLabel}` : `-# Error | $${cost} | ${duration} | ${turns} turns`;
|
|
2783
|
+
ctx.streamer.append(`
|
|
2784
|
+
${statusLine}`, { persist: false });
|
|
2785
|
+
if (!event.success && event.errors.length) {
|
|
2786
|
+
ctx.streamer.append(`
|
|
2787
|
+
\`\`\`
|
|
2788
|
+
${event.errors.join("\n")}
|
|
2789
|
+
\`\`\``, { persist: false });
|
|
2790
|
+
}
|
|
2791
|
+
await ctx.streamer.finalize();
|
|
2792
|
+
const session = getSessionView(ctx.sessionId);
|
|
2793
|
+
if (!session) {
|
|
2794
|
+
ctx.state.pendingAttachments = [];
|
|
2795
|
+
return;
|
|
2796
|
+
}
|
|
2797
|
+
if (ctx.mode === "monitor") {
|
|
2798
|
+
await flushDigest(ctx.sessionId);
|
|
2799
|
+
await updateSessionState(ctx.sessionId, {
|
|
2800
|
+
type: "work_started",
|
|
2801
|
+
sessionId: ctx.sessionId,
|
|
2802
|
+
source: providerSource(ctx.sessionId),
|
|
2803
|
+
confidence: "high",
|
|
2804
|
+
timestamp: Date.now(),
|
|
2805
|
+
metadata: {
|
|
2806
|
+
phase: "\u7B49\u5F85\u76D1\u7763\u5224\u65AD",
|
|
2807
|
+
summary: event.success ? "\u672C\u8F6E\u6267\u884C\u7ED3\u675F\uFF0C\u7B49\u5F85\u76D1\u7763\u5224\u65AD" : "\u672C\u8F6E\u6267\u884C\u5931\u8D25\uFF0C\u7B49\u5F85\u76D1\u7763\u5224\u65AD"
|
|
2808
|
+
}
|
|
2809
|
+
});
|
|
2810
|
+
} else {
|
|
2811
|
+
ctx.state.deferredResult = {
|
|
2812
|
+
event,
|
|
2813
|
+
text: lastText,
|
|
2814
|
+
attachments: [...ctx.state.pendingAttachments]
|
|
2815
|
+
};
|
|
2816
|
+
}
|
|
2817
|
+
ctx.state.pendingAttachments = [];
|
|
2818
|
+
};
|
|
2819
|
+
var errorEvent = async (event, ctx) => {
|
|
2820
|
+
console.warn(`[OutputHandler] Session ${ctx.sessionId}: error event \u2014 ${event.message}`);
|
|
2821
|
+
ctx.state.hadError = true;
|
|
2822
|
+
await ctx.streamer.finalize();
|
|
2823
|
+
queueDigest(ctx.sessionId, { kind: "error", text: `\u9519\u8BEF\uFF1A${truncate(event.message, 120)}` });
|
|
2824
|
+
if (ctx.mode === "monitor") return;
|
|
2825
|
+
const session = getSessionView(ctx.sessionId);
|
|
2826
|
+
if (!session) return;
|
|
2827
|
+
await flushDigest(ctx.sessionId);
|
|
2828
|
+
await updateSessionState(ctx.sessionId, {
|
|
2829
|
+
type: "errored",
|
|
2830
|
+
sessionId: ctx.sessionId,
|
|
2831
|
+
source: providerSource(ctx.sessionId),
|
|
2832
|
+
confidence: "high",
|
|
2833
|
+
timestamp: Date.now(),
|
|
2834
|
+
metadata: { errorMessage: event.message }
|
|
2835
|
+
});
|
|
2836
|
+
};
|
|
2837
|
+
var sessionInit = () => {
|
|
2838
|
+
};
|
|
2839
|
+
var EVENT_HANDLERS = {
|
|
2840
|
+
text_delta: textDelta,
|
|
2841
|
+
ask_user: askUser,
|
|
2842
|
+
task,
|
|
2843
|
+
task_started: taskStarted,
|
|
2844
|
+
task_progress: taskProgress,
|
|
2845
|
+
task_done: taskDone,
|
|
2846
|
+
web_search: webSearch,
|
|
2847
|
+
tool_start: toolStart,
|
|
2848
|
+
tool_result: toolResult,
|
|
2849
|
+
image_file: imageFile,
|
|
2850
|
+
command_execution: commandExecution,
|
|
2851
|
+
file_change: fileChange,
|
|
2852
|
+
reasoning,
|
|
2853
|
+
todo_list: todoList,
|
|
2854
|
+
result,
|
|
2855
|
+
error: errorEvent,
|
|
2856
|
+
session_init: sessionInit
|
|
2857
|
+
};
|
|
2858
|
+
async function dispatchEvent(event, ctx) {
|
|
2859
|
+
const handler = EVENT_HANDLERS[event.type];
|
|
2860
|
+
if (!handler) return;
|
|
2861
|
+
await handler(event, ctx);
|
|
2862
|
+
}
|
|
2863
|
+
|
|
2477
2864
|
// ../bot/src/output-handler.ts
|
|
2865
|
+
var DIGEST_FLUSH_INTERVAL_MS = 8e3;
|
|
2866
|
+
function createInitialState() {
|
|
2867
|
+
return {
|
|
2868
|
+
askedUser: false,
|
|
2869
|
+
hadError: false,
|
|
2870
|
+
success: null,
|
|
2871
|
+
commandCount: 0,
|
|
2872
|
+
fileChangeCount: 0,
|
|
2873
|
+
recentCommands: [],
|
|
2874
|
+
changedFiles: [],
|
|
2875
|
+
pendingAttachments: [],
|
|
2876
|
+
lastToolName: null,
|
|
2877
|
+
taskThreadMap: /* @__PURE__ */ new Map()
|
|
2878
|
+
};
|
|
2879
|
+
}
|
|
2478
2880
|
async function handleOutputStream(stream, channel, sessionId, verbose = false, mode = "auto", _provider = "claude", options = {}) {
|
|
2479
2881
|
const streamer = new MessageStreamer(channel, sessionId);
|
|
2480
|
-
console.log(
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
let hadError = false;
|
|
2485
|
-
let success = null;
|
|
2486
|
-
let commandCount = 0;
|
|
2487
|
-
let fileChangeCount = 0;
|
|
2488
|
-
const recentCommands = [];
|
|
2489
|
-
const changedFiles = [];
|
|
2490
|
-
const pendingAttachments = [];
|
|
2491
|
-
const taskThreadMap = /* @__PURE__ */ new Map();
|
|
2492
|
-
let deferredResult;
|
|
2882
|
+
console.log(
|
|
2883
|
+
`[OutputHandler] Stream started for session ${sessionId} (provider: ${_provider}, mode: ${mode}, verbose: ${verbose})`
|
|
2884
|
+
);
|
|
2885
|
+
const state = createInitialState();
|
|
2493
2886
|
let lastDigestFlushAt = Date.now();
|
|
2494
|
-
const session =
|
|
2887
|
+
const session = getSessionView(sessionId);
|
|
2495
2888
|
if (session) {
|
|
2496
2889
|
await initializeSessionPanel(sessionId, channel, {
|
|
2497
2890
|
statusCardMessageId: session.statusCardMessageId,
|
|
@@ -2506,238 +2899,34 @@ async function handleOutputStream(stream, channel, sessionId, verbose = false, m
|
|
|
2506
2899
|
timestamp: Date.now()
|
|
2507
2900
|
});
|
|
2508
2901
|
}
|
|
2902
|
+
const ctx = { sessionId, channel, streamer, verbose, mode, state };
|
|
2509
2903
|
try {
|
|
2510
2904
|
for await (const event of stream) {
|
|
2511
2905
|
options.onEvent?.(event);
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
streamer.append(event.text);
|
|
2515
|
-
break;
|
|
2516
|
-
}
|
|
2517
|
-
case "ask_user": {
|
|
2518
|
-
console.log(`[OutputHandler] Session ${sessionId}: ask_user event (human input requested)`);
|
|
2519
|
-
askedUser = true;
|
|
2520
|
-
askUserQuestionsJson = event.questionsJson;
|
|
2521
|
-
await streamer.discard();
|
|
2522
|
-
if (session) {
|
|
2523
|
-
await updateSessionState(sessionId, {
|
|
2524
|
-
type: "awaiting_human",
|
|
2525
|
-
sessionId,
|
|
2526
|
-
source: session.provider === "claude" ? "claude" : "codex",
|
|
2527
|
-
confidence: "high",
|
|
2528
|
-
timestamp: Date.now(),
|
|
2529
|
-
metadata: { detail: event.questionsJson }
|
|
2530
|
-
});
|
|
2531
|
-
await flushDigest(sessionId);
|
|
2532
|
-
await handleAwaitingHuman(sessionId, event.questionsJson, {
|
|
2533
|
-
source: session.provider === "claude" ? "claude" : "codex"
|
|
2534
|
-
});
|
|
2535
|
-
}
|
|
2536
|
-
break;
|
|
2537
|
-
}
|
|
2538
|
-
case "task": {
|
|
2539
|
-
await streamer.finalize();
|
|
2540
|
-
queueDigest(sessionId, { kind: "tool", text: `\u4EFB\u52A1\u5DE5\u5177\uFF1A${event.action}` });
|
|
2541
|
-
lastToolName = event.action;
|
|
2542
|
-
break;
|
|
2543
|
-
}
|
|
2544
|
-
case "task_started": {
|
|
2545
|
-
await streamer.finalize();
|
|
2546
|
-
queueDigest(sessionId, {
|
|
2547
|
-
kind: "subagent",
|
|
2548
|
-
text: `\u5B50\u4EE3\u7406\u542F\u52A8\uFF1A${truncate(event.description, 80)}`
|
|
2549
|
-
});
|
|
2550
|
-
if (session && channel.type !== void 0) {
|
|
2551
|
-
autoSpawnSubagentThread(session, event.taskId, event.description, channel).then((result) => {
|
|
2552
|
-
if (result) taskThreadMap.set(event.taskId, result.threadId);
|
|
2553
|
-
}).catch((err) => console.warn(`[OutputHandler] Failed to auto-spawn thread for task ${event.taskId}: ${err.message}`));
|
|
2554
|
-
}
|
|
2555
|
-
break;
|
|
2556
|
-
}
|
|
2557
|
-
case "task_progress": {
|
|
2558
|
-
if (event.summary) {
|
|
2559
|
-
queueDigest(sessionId, {
|
|
2560
|
-
kind: "subagent",
|
|
2561
|
-
text: `\u5B50\u4EE3\u7406\u8FDB\u5C55\uFF1A${truncate(event.summary, 100)}`
|
|
2562
|
-
});
|
|
2563
|
-
}
|
|
2564
|
-
const progressThreadId = taskThreadMap.get(event.taskId);
|
|
2565
|
-
if (progressThreadId && event.summary) {
|
|
2566
|
-
const thread = channel.threads?.cache.get(progressThreadId);
|
|
2567
|
-
if (thread) {
|
|
2568
|
-
thread.send(`\u{1F4DD} ${truncate(event.summary, 1900)}`).catch((e) => console.warn(`[OutputHandler] Failed to send progress to thread: ${e.message}`));
|
|
2569
|
-
}
|
|
2570
|
-
}
|
|
2571
|
-
break;
|
|
2572
|
-
}
|
|
2573
|
-
case "task_done": {
|
|
2574
|
-
await streamer.finalize();
|
|
2575
|
-
queueDigest(sessionId, {
|
|
2576
|
-
kind: "subagent",
|
|
2577
|
-
text: `\u5B50\u4EE3\u7406${event.status === "completed" ? "\u5B8C\u6210" : "\u7ED3\u675F"}\uFF1A${truncate(event.summary || "No summary.", 100)}`
|
|
2578
|
-
});
|
|
2579
|
-
const doneThreadId = taskThreadMap.get(event.taskId);
|
|
2580
|
-
if (doneThreadId) {
|
|
2581
|
-
const thread = channel.threads?.cache.get(doneThreadId);
|
|
2582
|
-
if (thread) {
|
|
2583
|
-
const statusEmoji = event.status === "completed" ? "\u2705" : "\u274C";
|
|
2584
|
-
thread.send(`${statusEmoji} \u5B50\u4EFB\u52A1${event.status === "completed" ? "\u5B8C\u6210" : "\u7ED3\u675F"}\uFF1A${truncate(event.summary || "", 1900)}`).catch((e) => console.warn(`[OutputHandler] Failed to send task done to thread: ${e.message}`));
|
|
2585
|
-
}
|
|
2586
|
-
taskThreadMap.delete(event.taskId);
|
|
2587
|
-
}
|
|
2588
|
-
break;
|
|
2589
|
-
}
|
|
2590
|
-
case "web_search": {
|
|
2591
|
-
if (verbose) {
|
|
2592
|
-
queueDigest(sessionId, { kind: "search", text: `\u68C0\u7D22\uFF1A${truncate(event.query, 80)}` });
|
|
2593
|
-
}
|
|
2594
|
-
break;
|
|
2595
|
-
}
|
|
2596
|
-
case "tool_start": {
|
|
2597
|
-
await streamer.finalize();
|
|
2598
|
-
queueDigest(sessionId, { kind: "tool", text: `\u5DE5\u5177\uFF1A${event.toolName}` });
|
|
2599
|
-
lastToolName = event.toolName;
|
|
2600
|
-
break;
|
|
2601
|
-
}
|
|
2602
|
-
case "tool_result": {
|
|
2603
|
-
await streamer.finalize();
|
|
2604
|
-
if (verbose && event.result) {
|
|
2605
|
-
queueDigest(sessionId, {
|
|
2606
|
-
kind: "tool",
|
|
2607
|
-
text: `\u5DE5\u5177\u7ED3\u679C\uFF1A${truncate(lastToolName || event.toolName || "tool", 60)}`
|
|
2608
|
-
});
|
|
2609
|
-
}
|
|
2610
|
-
break;
|
|
2611
|
-
}
|
|
2612
|
-
case "image_file": {
|
|
2613
|
-
if (existsSync(event.filePath)) {
|
|
2614
|
-
pendingAttachments.push(event.filePath);
|
|
2615
|
-
}
|
|
2616
|
-
break;
|
|
2617
|
-
}
|
|
2618
|
-
case "command_execution": {
|
|
2619
|
-
commandCount++;
|
|
2620
|
-
if (recentCommands.length < 8) recentCommands.push(event.command);
|
|
2621
|
-
if (!shouldSuppressCommandExecution(event.command)) {
|
|
2622
|
-
queueDigest(sessionId, {
|
|
2623
|
-
kind: "command",
|
|
2624
|
-
text: `\u547D\u4EE4\uFF1A${truncate(event.command, 80)}${event.exitCode !== null ? `\uFF08\u9000\u51FA\u7801 ${event.exitCode}\uFF09` : ""}`
|
|
2625
|
-
});
|
|
2626
|
-
}
|
|
2627
|
-
break;
|
|
2628
|
-
}
|
|
2629
|
-
case "file_change": {
|
|
2630
|
-
fileChangeCount += event.changes.length;
|
|
2631
|
-
for (const change of event.changes) {
|
|
2632
|
-
if (!change.filePath) continue;
|
|
2633
|
-
if (changedFiles.includes(change.filePath)) continue;
|
|
2634
|
-
if (changedFiles.length >= 12) break;
|
|
2635
|
-
changedFiles.push(change.filePath);
|
|
2636
|
-
}
|
|
2637
|
-
queueDigest(sessionId, {
|
|
2638
|
-
kind: "file",
|
|
2639
|
-
text: `\u6587\u4EF6\u53D8\u66F4\uFF1A${event.changes.length} \u4E2A\uFF08\u6700\u8FD1\uFF1A${truncate(changedFiles.slice(-3).join(", "), 120)}\uFF09`
|
|
2640
|
-
});
|
|
2641
|
-
break;
|
|
2642
|
-
}
|
|
2643
|
-
case "reasoning": {
|
|
2644
|
-
if (verbose) {
|
|
2645
|
-
queueDigest(sessionId, { kind: "reasoning", text: `\u63A8\u7406\uFF1A${truncate(event.text, 100)}` });
|
|
2646
|
-
}
|
|
2647
|
-
break;
|
|
2648
|
-
}
|
|
2649
|
-
case "todo_list": {
|
|
2650
|
-
queueDigest(sessionId, {
|
|
2651
|
-
kind: "todo",
|
|
2652
|
-
text: `\u5F85\u529E\u66F4\u65B0\uFF1A${event.items.filter((item) => item.completed).length}/${event.items.length} \u5DF2\u5B8C\u6210`
|
|
2653
|
-
});
|
|
2654
|
-
break;
|
|
2655
|
-
}
|
|
2656
|
-
case "result": {
|
|
2657
|
-
success = event.success;
|
|
2658
|
-
const lastText = streamer.getText();
|
|
2659
|
-
const cost = event.costUsd.toFixed(4);
|
|
2660
|
-
const duration = event.durationMs ? `${(event.durationMs / 1e3).toFixed(1)}s` : "unknown";
|
|
2661
|
-
const turns = event.numTurns || 0;
|
|
2662
|
-
const modeLabel = { auto: "\u81EA\u52A8", plan: "\u8BA1\u5212", normal: "\u666E\u901A", monitor: "\u76D1\u63A7" }[mode] || "\u81EA\u52A8";
|
|
2663
|
-
const statusLine = event.success ? `-# $${cost} | ${duration} | ${turns} turns | ${modeLabel}` : `-# Error | $${cost} | ${duration} | ${turns} turns`;
|
|
2664
|
-
streamer.append(`
|
|
2665
|
-
${statusLine}`, { persist: false });
|
|
2666
|
-
if (!event.success && event.errors.length) {
|
|
2667
|
-
streamer.append(`
|
|
2668
|
-
\`\`\`
|
|
2669
|
-
${event.errors.join("\n")}
|
|
2670
|
-
\`\`\``, { persist: false });
|
|
2671
|
-
}
|
|
2672
|
-
await streamer.finalize();
|
|
2673
|
-
if (session) {
|
|
2674
|
-
if (mode === "monitor") {
|
|
2675
|
-
await flushDigest(sessionId);
|
|
2676
|
-
await updateSessionState(sessionId, {
|
|
2677
|
-
type: "work_started",
|
|
2678
|
-
sessionId,
|
|
2679
|
-
source: session.provider === "claude" ? "claude" : "codex",
|
|
2680
|
-
confidence: "high",
|
|
2681
|
-
timestamp: Date.now(),
|
|
2682
|
-
metadata: {
|
|
2683
|
-
phase: "\u7B49\u5F85\u76D1\u7763\u5224\u65AD",
|
|
2684
|
-
summary: event.success ? "\u672C\u8F6E\u6267\u884C\u7ED3\u675F\uFF0C\u7B49\u5F85\u76D1\u7763\u5224\u65AD" : "\u672C\u8F6E\u6267\u884C\u5931\u8D25\uFF0C\u7B49\u5F85\u76D1\u7763\u5224\u65AD"
|
|
2685
|
-
}
|
|
2686
|
-
});
|
|
2687
|
-
} else {
|
|
2688
|
-
deferredResult = {
|
|
2689
|
-
event,
|
|
2690
|
-
text: lastText,
|
|
2691
|
-
attachments: [...pendingAttachments]
|
|
2692
|
-
};
|
|
2693
|
-
}
|
|
2694
|
-
}
|
|
2695
|
-
pendingAttachments.length = 0;
|
|
2696
|
-
break;
|
|
2697
|
-
}
|
|
2698
|
-
case "error": {
|
|
2699
|
-
console.warn(`[OutputHandler] Session ${sessionId}: error event \u2014 ${event.message}`);
|
|
2700
|
-
hadError = true;
|
|
2701
|
-
await streamer.finalize();
|
|
2702
|
-
queueDigest(sessionId, { kind: "error", text: `\u9519\u8BEF\uFF1A${truncate(event.message, 120)}` });
|
|
2703
|
-
if (session && mode !== "monitor") {
|
|
2704
|
-
await flushDigest(sessionId);
|
|
2705
|
-
await updateSessionState(sessionId, {
|
|
2706
|
-
type: "errored",
|
|
2707
|
-
sessionId,
|
|
2708
|
-
source: session.provider === "claude" ? "claude" : "codex",
|
|
2709
|
-
confidence: "high",
|
|
2710
|
-
timestamp: Date.now(),
|
|
2711
|
-
metadata: { errorMessage: event.message }
|
|
2712
|
-
});
|
|
2713
|
-
}
|
|
2714
|
-
break;
|
|
2715
|
-
}
|
|
2716
|
-
case "session_init": {
|
|
2717
|
-
break;
|
|
2718
|
-
}
|
|
2719
|
-
}
|
|
2720
|
-
if (session && Date.now() - lastDigestFlushAt >= 8e3) {
|
|
2906
|
+
await dispatchEvent(event, ctx);
|
|
2907
|
+
if (session && Date.now() - lastDigestFlushAt >= DIGEST_FLUSH_INTERVAL_MS) {
|
|
2721
2908
|
await flushDigest(sessionId);
|
|
2722
2909
|
lastDigestFlushAt = Date.now();
|
|
2723
2910
|
}
|
|
2724
2911
|
}
|
|
2725
|
-
if (session && mode !== "monitor" && deferredResult) {
|
|
2726
|
-
console.log(
|
|
2912
|
+
if (session && mode !== "monitor" && state.deferredResult) {
|
|
2913
|
+
console.log(
|
|
2914
|
+
`[OutputHandler] Session ${sessionId}: delivering deferred result (success: ${state.deferredResult.event.success})`
|
|
2915
|
+
);
|
|
2727
2916
|
await flushDigest(sessionId);
|
|
2728
2917
|
await handleResultEvent(
|
|
2729
2918
|
sessionId,
|
|
2730
|
-
deferredResult.event,
|
|
2731
|
-
deferredResult.text,
|
|
2732
|
-
deferredResult.attachments
|
|
2919
|
+
state.deferredResult.event,
|
|
2920
|
+
state.deferredResult.text,
|
|
2921
|
+
state.deferredResult.attachments
|
|
2733
2922
|
);
|
|
2734
2923
|
}
|
|
2735
2924
|
} catch (err) {
|
|
2736
|
-
hadError = true;
|
|
2925
|
+
state.hadError = true;
|
|
2737
2926
|
await streamer.finalize();
|
|
2738
2927
|
if (!isAbortError(err)) {
|
|
2739
|
-
console.error(`[OutputHandler] Session ${sessionId}: unhandled stream error \u2014 ${err.message || ""}`);
|
|
2740
2928
|
const errMsg = err.message || "";
|
|
2929
|
+
console.error(`[OutputHandler] Session ${sessionId}: unhandled stream error \u2014 ${errMsg}`);
|
|
2741
2930
|
queueDigest(sessionId, { kind: "error", text: `\u5F02\u5E38\uFF1A${truncate(errMsg, 120)}` });
|
|
2742
2931
|
if (session) {
|
|
2743
2932
|
await flushDigest(sessionId);
|
|
@@ -2755,37 +2944,56 @@ ${event.errors.join("\n")}
|
|
|
2755
2944
|
streamer.destroy();
|
|
2756
2945
|
}
|
|
2757
2946
|
const finalText = streamer.getText();
|
|
2758
|
-
console.log(
|
|
2947
|
+
console.log(
|
|
2948
|
+
`[OutputHandler] Stream ended for session ${sessionId} (text: ${finalText.length} chars, commands: ${state.commandCount}, files: ${state.fileChangeCount}, success: ${state.success}, hadError: ${state.hadError})`
|
|
2949
|
+
);
|
|
2759
2950
|
return {
|
|
2760
2951
|
text: finalText,
|
|
2761
|
-
askedUser,
|
|
2762
|
-
askUserQuestionsJson,
|
|
2763
|
-
hadError,
|
|
2764
|
-
success,
|
|
2765
|
-
commandCount,
|
|
2766
|
-
fileChangeCount,
|
|
2767
|
-
recentCommands,
|
|
2768
|
-
changedFiles
|
|
2952
|
+
askedUser: state.askedUser,
|
|
2953
|
+
askUserQuestionsJson: state.askUserQuestionsJson,
|
|
2954
|
+
hadError: state.hadError,
|
|
2955
|
+
success: state.success,
|
|
2956
|
+
commandCount: state.commandCount,
|
|
2957
|
+
fileChangeCount: state.fileChangeCount,
|
|
2958
|
+
recentCommands: state.recentCommands,
|
|
2959
|
+
changedFiles: state.changedFiles
|
|
2769
2960
|
};
|
|
2770
2961
|
}
|
|
2771
2962
|
|
|
2772
2963
|
// ../bot/src/discord-output-port.ts
|
|
2964
|
+
function asSessionChannel(ref) {
|
|
2965
|
+
return ref;
|
|
2966
|
+
}
|
|
2967
|
+
function toResultEvent(data) {
|
|
2968
|
+
return {
|
|
2969
|
+
type: "result",
|
|
2970
|
+
success: data.success,
|
|
2971
|
+
costUsd: data.costUsd,
|
|
2972
|
+
durationMs: data.durationMs,
|
|
2973
|
+
numTurns: data.numTurns,
|
|
2974
|
+
errors: data.errors,
|
|
2975
|
+
metadata: data.metadata
|
|
2976
|
+
};
|
|
2977
|
+
}
|
|
2773
2978
|
var DiscordOutputPort = class {
|
|
2774
2979
|
async initializePanel(session, channel) {
|
|
2775
|
-
await initializeSessionPanel(session.id, channel);
|
|
2980
|
+
await initializeSessionPanel(session.id, asSessionChannel(channel));
|
|
2776
2981
|
}
|
|
2777
2982
|
async updateState(sessionId, event, options) {
|
|
2778
|
-
await updateSessionState(
|
|
2983
|
+
await updateSessionState(
|
|
2984
|
+
sessionId,
|
|
2985
|
+
event,
|
|
2986
|
+
options?.channel ? { channel: asSessionChannel(options.channel) } : void 0
|
|
2987
|
+
);
|
|
2779
2988
|
}
|
|
2780
2989
|
async handleResult(sessionId, resultEvent, summary) {
|
|
2781
|
-
|
|
2782
|
-
await handleResultEvent(sessionId, event, summary ?? "");
|
|
2990
|
+
await handleResultEvent(sessionId, toResultEvent(resultEvent), summary ?? "");
|
|
2783
2991
|
}
|
|
2784
2992
|
async handleAwaitingHuman(sessionId, reason, options) {
|
|
2785
2993
|
await handleAwaitingHuman(sessionId, reason, options);
|
|
2786
2994
|
}
|
|
2787
2995
|
async relocatePanel(sessionId, channel) {
|
|
2788
|
-
await relocateSessionPanelToBottom(sessionId, channel);
|
|
2996
|
+
await relocateSessionPanelToBottom(sessionId, asSessionChannel(channel));
|
|
2789
2997
|
}
|
|
2790
2998
|
cleanupPanel(sessionId) {
|
|
2791
2999
|
cleanupSessionPanel(sessionId);
|
|
@@ -2796,7 +3004,7 @@ var DiscordOutputPort = class {
|
|
|
2796
3004
|
async handleOutputStream(stream, channel, sessionId, verbose = false, mode = "auto", provider = "claude", options = {}) {
|
|
2797
3005
|
return handleOutputStream(
|
|
2798
3006
|
stream,
|
|
2799
|
-
channel,
|
|
3007
|
+
asSessionChannel(channel),
|
|
2800
3008
|
sessionId,
|
|
2801
3009
|
verbose,
|
|
2802
3010
|
mode,
|
|
@@ -2927,36 +3135,36 @@ function buildProjectCleanupPreview(input) {
|
|
|
2927
3135
|
return preview;
|
|
2928
3136
|
}
|
|
2929
3137
|
async function archiveSessionsById(guild, sessionIds, summary = "Bulk cleanup from Discord command") {
|
|
2930
|
-
const
|
|
3138
|
+
const result2 = {
|
|
2931
3139
|
archivedSessions: 0,
|
|
2932
3140
|
skippedGenerating: 0,
|
|
2933
3141
|
missingSessions: 0,
|
|
2934
3142
|
failed: []
|
|
2935
3143
|
};
|
|
2936
3144
|
for (const sessionId of new Set(Array.from(sessionIds).filter(Boolean))) {
|
|
2937
|
-
const session =
|
|
3145
|
+
const session = getSessionView(sessionId);
|
|
2938
3146
|
if (!session || session.type !== "persistent") {
|
|
2939
|
-
|
|
3147
|
+
result2.missingSessions += 1;
|
|
2940
3148
|
continue;
|
|
2941
3149
|
}
|
|
2942
3150
|
if (session.isGenerating) {
|
|
2943
|
-
|
|
3151
|
+
result2.skippedGenerating += 1;
|
|
2944
3152
|
continue;
|
|
2945
3153
|
}
|
|
2946
3154
|
try {
|
|
2947
3155
|
await archiveSession(session, guild, summary);
|
|
2948
|
-
|
|
3156
|
+
result2.archivedSessions += 1;
|
|
2949
3157
|
} catch (error) {
|
|
2950
3158
|
console.error(`[Housekeeping] Failed to archive session ${sessionId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
2951
|
-
|
|
3159
|
+
result2.failed.push({
|
|
2952
3160
|
sessionId: session.id,
|
|
2953
3161
|
channelId: session.channelId,
|
|
2954
3162
|
message: error instanceof Error ? error.message : String(error)
|
|
2955
3163
|
});
|
|
2956
3164
|
}
|
|
2957
3165
|
}
|
|
2958
|
-
console.log(`[Housekeeping] Archive result: ${
|
|
2959
|
-
return
|
|
3166
|
+
console.log(`[Housekeeping] Archive result: ${result2.archivedSessions} archived, ${result2.skippedGenerating} skipped, ${result2.missingSessions} missing, ${result2.failed.length} failed`);
|
|
3167
|
+
return result2;
|
|
2960
3168
|
}
|
|
2961
3169
|
async function reconcileSessionRecordsWithGuild(guild) {
|
|
2962
3170
|
const sessions = getAllSessions();
|
|
@@ -3446,6 +3654,7 @@ var POLL_INTERVAL_IDLE_MS = 5e3;
|
|
|
3446
3654
|
var STALE_CLEANUP_MS = 12e4;
|
|
3447
3655
|
var MAX_LINES_PER_POLL = 100;
|
|
3448
3656
|
var MAX_BUFFER_SIZE = 10 * 1024 * 1024;
|
|
3657
|
+
var MAX_FILE_SIZE_BYTES = 500 * 1024 * 1024;
|
|
3449
3658
|
var CodexLogMonitor = class {
|
|
3450
3659
|
tracked = /* @__PURE__ */ new Map();
|
|
3451
3660
|
interval = null;
|
|
@@ -3539,6 +3748,14 @@ var CodexLogMonitor = class {
|
|
|
3539
3748
|
} catch {
|
|
3540
3749
|
return;
|
|
3541
3750
|
}
|
|
3751
|
+
if (stat.size > MAX_FILE_SIZE_BYTES) {
|
|
3752
|
+
if (!this.tracked.has(filePath)) {
|
|
3753
|
+
console.warn(
|
|
3754
|
+
`[CodexLogMonitor] Skipping oversized rollout file (${Math.round(stat.size / 1024 / 1024)}MB): ${filePath}`
|
|
3755
|
+
);
|
|
3756
|
+
}
|
|
3757
|
+
return;
|
|
3758
|
+
}
|
|
3542
3759
|
let tracked = this.tracked.get(filePath);
|
|
3543
3760
|
if (!tracked) {
|
|
3544
3761
|
const sessionId = this.extractSessionId(fileName);
|
|
@@ -3785,7 +4002,7 @@ async function handleCodexMonitorStateChange(resolveChannel2, monitorSessionId,
|
|
|
3785
4002
|
|
|
3786
4003
|
// ../bot/src/ipc-server.ts
|
|
3787
4004
|
import { createServer } from "net";
|
|
3788
|
-
import { unlinkSync, existsSync as existsSync3 } from "fs";
|
|
4005
|
+
import { unlinkSync, existsSync as existsSync3, chmodSync } from "fs";
|
|
3789
4006
|
|
|
3790
4007
|
// ../bot/src/session-discovery.ts
|
|
3791
4008
|
async function discoverAndRegisterSession(client2, params) {
|
|
@@ -3794,7 +4011,7 @@ async function discoverAndRegisterSession(client2, params) {
|
|
|
3794
4011
|
console.warn("[Session Discovery] No guild found, cannot register local session");
|
|
3795
4012
|
return null;
|
|
3796
4013
|
}
|
|
3797
|
-
const
|
|
4014
|
+
const result2 = await registerLocalSession(
|
|
3798
4015
|
{
|
|
3799
4016
|
provider: params.provider,
|
|
3800
4017
|
providerSessionId: params.providerSessionId,
|
|
@@ -3806,11 +4023,11 @@ async function discoverAndRegisterSession(client2, params) {
|
|
|
3806
4023
|
},
|
|
3807
4024
|
guild
|
|
3808
4025
|
);
|
|
3809
|
-
if (!
|
|
4026
|
+
if (!result2) return null;
|
|
3810
4027
|
return {
|
|
3811
|
-
sessionId:
|
|
3812
|
-
channelId:
|
|
3813
|
-
isNew:
|
|
4028
|
+
sessionId: result2.session.id,
|
|
4029
|
+
channelId: result2.session.channelId,
|
|
4030
|
+
isNew: result2.isNewlyCreated
|
|
3814
4031
|
};
|
|
3815
4032
|
}
|
|
3816
4033
|
|
|
@@ -3871,6 +4088,15 @@ function startIpcServer(client2) {
|
|
|
3871
4088
|
});
|
|
3872
4089
|
});
|
|
3873
4090
|
server.listen(socketPath, () => {
|
|
4091
|
+
if (process.platform !== "win32") {
|
|
4092
|
+
try {
|
|
4093
|
+
chmodSync(socketPath, 384);
|
|
4094
|
+
} catch (err) {
|
|
4095
|
+
console.warn(
|
|
4096
|
+
`[IpcServer] Failed to set 0600 on socket ${socketPath}: ${err.message}`
|
|
4097
|
+
);
|
|
4098
|
+
}
|
|
4099
|
+
}
|
|
3874
4100
|
console.log(`[IpcServer] Listening on ${socketPath}`);
|
|
3875
4101
|
});
|
|
3876
4102
|
server.on("error", (err) => {
|
|
@@ -3941,7 +4167,7 @@ async function handleHookEvent(payload) {
|
|
|
3941
4167
|
} : void 0
|
|
3942
4168
|
});
|
|
3943
4169
|
if (registered) {
|
|
3944
|
-
session =
|
|
4170
|
+
session = getSessionView(registered.sessionId);
|
|
3945
4171
|
console.log(`[IpcServer] Auto-registered session: ${registered.sessionId}`);
|
|
3946
4172
|
}
|
|
3947
4173
|
}
|
|
@@ -3961,14 +4187,14 @@ async function handleHookEvent(payload) {
|
|
|
3961
4187
|
async function handleGateResolved(payload) {
|
|
3962
4188
|
const data = payload;
|
|
3963
4189
|
console.log(`[IpcServer] Terminal resolved gate ${data.gateId}: ${data.action}`);
|
|
3964
|
-
const
|
|
3965
|
-
if (!
|
|
3966
|
-
console.warn(`[IpcServer] Gate resolution failed: ${
|
|
4190
|
+
const result2 = gateService.notifyTerminalResolved(data.gateId, data.action);
|
|
4191
|
+
if (!result2.success) {
|
|
4192
|
+
console.warn(`[IpcServer] Gate resolution failed: ${result2.message}`);
|
|
3967
4193
|
return;
|
|
3968
4194
|
}
|
|
3969
|
-
const gate =
|
|
4195
|
+
const gate = gateService.getGate(data.gateId);
|
|
3970
4196
|
if (gate?.discordMessageId) {
|
|
3971
|
-
const session =
|
|
4197
|
+
const session = getSessionView(data.sessionId);
|
|
3972
4198
|
if (session) {
|
|
3973
4199
|
const channel = discordClient?.channels.cache.get(session.channelId);
|
|
3974
4200
|
if (channel) {
|
|
@@ -4656,7 +4882,9 @@ var BotServicesOrchestrator = class {
|
|
|
4656
4882
|
logBuffer2.log(`Reconciled ${reconciled.endedMissingSessions} stale session record(s) on startup.`);
|
|
4657
4883
|
}
|
|
4658
4884
|
setBotStartTime(Date.now());
|
|
4659
|
-
await
|
|
4885
|
+
await gateService.init();
|
|
4886
|
+
await this.#reconcilePendingGates(client2, logBuffer2);
|
|
4887
|
+
await this.#resumeAbandonedMonitorRuns(client2, logBuffer2);
|
|
4660
4888
|
if (config.messageRetentionDays) {
|
|
4661
4889
|
await cleanupOldMessages(client2);
|
|
4662
4890
|
}
|
|
@@ -4667,15 +4895,55 @@ var BotServicesOrchestrator = class {
|
|
|
4667
4895
|
logBuffer2.log("Codex log monitor started");
|
|
4668
4896
|
return { serviceBus: this.#serviceBus, logBuffer: logBuffer2, presenceManager, logChannel, codexMonitor: null };
|
|
4669
4897
|
}
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4898
|
+
/**
|
|
4899
|
+
* 重启后对悬挂的 Monitor run 执行 reconcile,并按 config.monitorAutoResumePolicy 续跑符合条件的 session。
|
|
4900
|
+
* 续跑采用 fire-and-forget:每个 session 独立异步运行,不阻塞启动。
|
|
4901
|
+
*/
|
|
4902
|
+
async #resumeAbandonedMonitorRuns(client2, logBuffer2) {
|
|
4903
|
+
let result2;
|
|
4904
|
+
try {
|
|
4905
|
+
result2 = await reconcileAndCollectAutoResumeCandidates(config.monitorAutoResumePolicy);
|
|
4906
|
+
} catch (err) {
|
|
4907
|
+
console.error("[MonitorAutoResume] reconcile failed:", err);
|
|
4908
|
+
return;
|
|
4909
|
+
}
|
|
4910
|
+
if (result2.abandoned.length > 0) {
|
|
4911
|
+
logBuffer2.log(
|
|
4912
|
+
`Marked ${result2.abandoned.length} orphan monitor run(s) as abandoned on startup.`
|
|
4913
|
+
);
|
|
4914
|
+
}
|
|
4915
|
+
if (result2.candidates.length === 0) return;
|
|
4916
|
+
logBuffer2.log(
|
|
4917
|
+
`Auto-resuming ${result2.candidates.length} monitor session(s) (policy=${config.monitorAutoResumePolicy}).`
|
|
4918
|
+
);
|
|
4919
|
+
for (const candidate of result2.candidates) {
|
|
4920
|
+
const session = getSessionView(candidate.sessionId);
|
|
4921
|
+
if (!session) continue;
|
|
4922
|
+
const channel = client2.channels.cache.get(candidate.channelId);
|
|
4923
|
+
if (!channel) {
|
|
4924
|
+
console.warn(
|
|
4925
|
+
`[MonitorAutoResume] sessionId=${candidate.sessionId} channel ${candidate.channelId} not accessible, skipping`
|
|
4926
|
+
);
|
|
4927
|
+
continue;
|
|
4928
|
+
}
|
|
4929
|
+
console.log(
|
|
4930
|
+
`[MonitorAutoResume] resuming sessionId=${candidate.sessionId} runId=${candidate.runId} lastIteration=${candidate.lastIteration}`
|
|
4931
|
+
);
|
|
4932
|
+
void executeSessionContinue(session, channel).catch((err) => {
|
|
4933
|
+
console.error(
|
|
4934
|
+
`[MonitorAutoResume] sessionId=${candidate.sessionId} resume failed:`,
|
|
4935
|
+
err
|
|
4936
|
+
);
|
|
4937
|
+
});
|
|
4938
|
+
}
|
|
4939
|
+
}
|
|
4940
|
+
async #reconcilePendingGates(client2, logBuffer2) {
|
|
4941
|
+
const result2 = gateService.reconcileOnStartup(config.gateRestartPolicy);
|
|
4942
|
+
for (const { gateId, discordMessageId } of result2.invalidated) {
|
|
4675
4943
|
if (!discordMessageId) continue;
|
|
4676
|
-
const gate =
|
|
4944
|
+
const gate = gateService.getGate(gateId);
|
|
4677
4945
|
if (!gate?.sessionId) continue;
|
|
4678
|
-
const session =
|
|
4946
|
+
const session = getSessionView(gate.sessionId);
|
|
4679
4947
|
if (!session) continue;
|
|
4680
4948
|
const channel = client2.channels.cache.get(session.channelId);
|
|
4681
4949
|
if (!channel?.messages) continue;
|
|
@@ -4692,10 +4960,17 @@ var BotServicesOrchestrator = class {
|
|
|
4692
4960
|
}))
|
|
4693
4961
|
});
|
|
4694
4962
|
} catch (err) {
|
|
4695
|
-
console.error(`[
|
|
4963
|
+
console.error(`[GateReconcile] Failed to update message for gate ${gateId}:`, err);
|
|
4696
4964
|
}
|
|
4697
4965
|
}
|
|
4698
|
-
|
|
4966
|
+
if (result2.resumed.length > 0) {
|
|
4967
|
+
logBuffer2.log(
|
|
4968
|
+
`Resumed ${result2.resumed.length} pending gate(s) across restart (policy=resume-pending).`
|
|
4969
|
+
);
|
|
4970
|
+
}
|
|
4971
|
+
if (result2.invalidated.length > 0) {
|
|
4972
|
+
logBuffer2.log(`Closed ${result2.invalidated.length} orphan/overdue gate(s) on startup.`);
|
|
4973
|
+
}
|
|
4699
4974
|
}
|
|
4700
4975
|
#registerServices(client2, logBuffer2, presence) {
|
|
4701
4976
|
this.#serviceBus.register({ name: "message-handler", start() {
|
|
@@ -4720,10 +4995,10 @@ var BotServicesOrchestrator = class {
|
|
|
4720
4995
|
);
|
|
4721
4996
|
},
|
|
4722
4997
|
async (providerSessionId, cwd, remoteHumanControl, subagent) => {
|
|
4723
|
-
const { registerLocalSession: registerLocalSession2 } = await import("./session-local-registration-
|
|
4998
|
+
const { registerLocalSession: registerLocalSession2 } = await import("./session-local-registration-MISPPGXF.js");
|
|
4724
4999
|
const g = client2.guilds.cache.first();
|
|
4725
5000
|
if (!g) return false;
|
|
4726
|
-
const
|
|
5001
|
+
const result2 = await registerLocalSession2(
|
|
4727
5002
|
{
|
|
4728
5003
|
provider: "codex",
|
|
4729
5004
|
providerSessionId,
|
|
@@ -4735,10 +5010,10 @@ var BotServicesOrchestrator = class {
|
|
|
4735
5010
|
},
|
|
4736
5011
|
g
|
|
4737
5012
|
);
|
|
4738
|
-
if (
|
|
4739
|
-
void notifyUnmanagedCodexHint(client2,
|
|
5013
|
+
if (result2?.isNewlyCreated && result2.session.remoteHumanControl === false) {
|
|
5014
|
+
void notifyUnmanagedCodexHint(client2, result2.session.id, result2.session.channelId);
|
|
4740
5015
|
}
|
|
4741
|
-
return
|
|
5016
|
+
return result2 !== null;
|
|
4742
5017
|
}
|
|
4743
5018
|
);
|
|
4744
5019
|
this.#serviceBus.register({
|
|
@@ -4768,8 +5043,8 @@ var BotServicesOrchestrator = class {
|
|
|
4768
5043
|
stopPerformanceMonitoring();
|
|
4769
5044
|
} });
|
|
4770
5045
|
this.#serviceBus.register(intervalService("gate-housekeeping", () => {
|
|
4771
|
-
const expired =
|
|
4772
|
-
const archived =
|
|
5046
|
+
const expired = gateService.cleanupExpired();
|
|
5047
|
+
const archived = gateService.archiveResolved(100);
|
|
4773
5048
|
if (expired || archived) console.log(`[GateHousekeeping] expired=${expired}, archived=${archived}`);
|
|
4774
5049
|
}, 6e4));
|
|
4775
5050
|
this.#serviceBus.register(intervalService("presence", () => presence.updatePresence(), 3e4));
|
|
@@ -4874,7 +5149,7 @@ var PROVIDER_COLORS = {
|
|
|
4874
5149
|
claude: 3447003,
|
|
4875
5150
|
codex: 1090431
|
|
4876
5151
|
};
|
|
4877
|
-
var
|
|
5152
|
+
var MODE_LABELS2 = {
|
|
4878
5153
|
auto: "\u26A1 \u81EA\u52A8\u6A21\u5F0F \u2014 \u5B8C\u5168\u81EA\u4E3B",
|
|
4879
5154
|
plan: "\u{1F4CB} \u8BA1\u5212\u6A21\u5F0F \u2014 \u53D8\u66F4\u524D\u5148\u89C4\u5212",
|
|
4880
5155
|
normal: "\u{1F6E1}\uFE0F \u666E\u901A\u6A21\u5F0F \u2014 \u7834\u574F\u6027\u64CD\u4F5C\u524D\u786E\u8BA4",
|
|
@@ -4884,7 +5159,7 @@ var CONTROL_CHANNEL_NAME = "control";
|
|
|
4884
5159
|
var CLEANUP_PREVIEW_LIST_LIMIT = 10;
|
|
4885
5160
|
var CLEANUP_PREVIEW_LABEL_LIMIT = 120;
|
|
4886
5161
|
async function registerStatusCardWithPanelAdapter(sessionId, channel, statusCardMessageId) {
|
|
4887
|
-
const { registerExistingStatusCard: registerExistingStatusCard2 } = await import("./panel-adapter-
|
|
5162
|
+
const { registerExistingStatusCard: registerExistingStatusCard2 } = await import("./panel-adapter-U75WXDLB.js");
|
|
4888
5163
|
if (typeof registerExistingStatusCard2 !== "function") {
|
|
4889
5164
|
log(`[panel-adapter] registerExistingStatusCard \u672A\u66B4\u9732\uFF0Csession=${sessionId}`);
|
|
4890
5165
|
return false;
|
|
@@ -5514,7 +5789,7 @@ async function handleAgentSpawn(interaction) {
|
|
|
5514
5789
|
const embed = new EmbedBuilder4().setColor(3066993).setTitle(`\u2705 Agent \u5DF2\u521B\u5EFA\uFF1A${label}`).addFields(
|
|
5515
5790
|
{ name: "\u9891\u9053", value: `<#${sessionChannel.id}>`, inline: true },
|
|
5516
5791
|
{ name: "\u63D0\u4F9B\u5546", value: PROVIDER_LABELS[provider], inline: true },
|
|
5517
|
-
{ name: "\u6A21\u5F0F", value:
|
|
5792
|
+
{ name: "\u6A21\u5F0F", value: MODE_LABELS2?.[mode] ?? mode, inline: false },
|
|
5518
5793
|
{ name: "\u76EE\u5F55", value: `\`${session.directory}\``, inline: false }
|
|
5519
5794
|
);
|
|
5520
5795
|
if (provider === "claude" && session.claudePermissionMode) {
|
|
@@ -5682,7 +5957,7 @@ async function handleAgentMode(interaction) {
|
|
|
5682
5957
|
}
|
|
5683
5958
|
const mode = interaction.options.getString("mode", true);
|
|
5684
5959
|
setMode(session.id, mode);
|
|
5685
|
-
await interaction.reply({ content: `\u6A21\u5F0F\u5DF2\u8BBE\u4E3A **${
|
|
5960
|
+
await interaction.reply({ content: `\u6A21\u5F0F\u5DF2\u8BBE\u4E3A **${MODE_LABELS2?.[mode] ?? mode}**\u3002`, ephemeral: true });
|
|
5686
5961
|
}
|
|
5687
5962
|
async function handleAgentGoal(interaction) {
|
|
5688
5963
|
const session = getSessionByChannel(interaction.channelId);
|
|
@@ -5736,7 +6011,7 @@ async function handleAgentPermissions(interaction) {
|
|
|
5736
6011
|
return;
|
|
5737
6012
|
}
|
|
5738
6013
|
await updateSessionPermissions(session.id, patch);
|
|
5739
|
-
const refreshed =
|
|
6014
|
+
const refreshed = getSessionView(session.id) ?? { ...session, ...patch };
|
|
5740
6015
|
const timing = session.isGenerating ? "\u5DF2\u4FDD\u5B58\uFF0C\u5C06\u5728\u4E0B\u4E00\u8F6E\u751F\u6548\u3002" : "\u5DF2\u66F4\u65B0\u5E76\u7ACB\u5373\u751F\u6548\u3002";
|
|
5741
6016
|
await interaction.reply({
|
|
5742
6017
|
content: `${timing}
|
|
@@ -5912,13 +6187,13 @@ var joinToUint8Array = (uint8ArraysOrStrings) => {
|
|
|
5912
6187
|
};
|
|
5913
6188
|
var stringsToUint8Arrays = (uint8ArraysOrStrings) => uint8ArraysOrStrings.map((uint8ArrayOrString) => typeof uint8ArrayOrString === "string" ? stringToUint8Array(uint8ArrayOrString) : uint8ArrayOrString);
|
|
5914
6189
|
var concatUint8Arrays = (uint8Arrays) => {
|
|
5915
|
-
const
|
|
6190
|
+
const result2 = new Uint8Array(getJoinLength(uint8Arrays));
|
|
5916
6191
|
let index = 0;
|
|
5917
6192
|
for (const uint8Array of uint8Arrays) {
|
|
5918
|
-
|
|
6193
|
+
result2.set(uint8Array, index);
|
|
5919
6194
|
index += uint8Array.length;
|
|
5920
6195
|
}
|
|
5921
|
-
return
|
|
6196
|
+
return result2;
|
|
5922
6197
|
};
|
|
5923
6198
|
var getJoinLength = (uint8Arrays) => {
|
|
5924
6199
|
let joinLength = 0;
|
|
@@ -6473,17 +6748,17 @@ var format = (open2, close) => {
|
|
|
6473
6748
|
if (index === -1) {
|
|
6474
6749
|
return openCode + string + closeCode;
|
|
6475
6750
|
}
|
|
6476
|
-
let
|
|
6751
|
+
let result2 = openCode;
|
|
6477
6752
|
let lastIndex = 0;
|
|
6478
6753
|
const reopenOnNestedClose = close === 22;
|
|
6479
6754
|
const replaceCode = (reopenOnNestedClose ? closeCode : "") + openCode;
|
|
6480
6755
|
while (index !== -1) {
|
|
6481
|
-
|
|
6756
|
+
result2 += string.slice(lastIndex, index) + replaceCode;
|
|
6482
6757
|
lastIndex = index + closeCode.length;
|
|
6483
6758
|
index = string.indexOf(closeCode, lastIndex);
|
|
6484
6759
|
}
|
|
6485
|
-
|
|
6486
|
-
return
|
|
6760
|
+
result2 += string.slice(lastIndex) + closeCode;
|
|
6761
|
+
return result2;
|
|
6487
6762
|
};
|
|
6488
6763
|
};
|
|
6489
6764
|
var reset = format(0, 0);
|
|
@@ -6585,8 +6860,8 @@ var appendNewline = (printedLine) => printedLine.endsWith("\n") ? printedLine :
|
|
|
6585
6860
|
`;
|
|
6586
6861
|
|
|
6587
6862
|
// ../../node_modules/.pnpm/execa@9.6.1/node_modules/execa/lib/verbose/log.js
|
|
6588
|
-
var verboseLog = ({ type, verboseMessage, fdNumber, verboseInfo, result }) => {
|
|
6589
|
-
const verboseObject = getVerboseObject({ type, result, verboseInfo });
|
|
6863
|
+
var verboseLog = ({ type, verboseMessage, fdNumber, verboseInfo, result: result2 }) => {
|
|
6864
|
+
const verboseObject = getVerboseObject({ type, result: result2, verboseInfo });
|
|
6590
6865
|
const printedLines = getPrintedLines(verboseMessage, verboseObject);
|
|
6591
6866
|
const finalLines = applyVerboseOnLines(printedLines, verboseInfo, fdNumber);
|
|
6592
6867
|
if (finalLines !== "") {
|
|
@@ -6595,7 +6870,7 @@ var verboseLog = ({ type, verboseMessage, fdNumber, verboseInfo, result }) => {
|
|
|
6595
6870
|
};
|
|
6596
6871
|
var getVerboseObject = ({
|
|
6597
6872
|
type,
|
|
6598
|
-
result,
|
|
6873
|
+
result: result2,
|
|
6599
6874
|
verboseInfo: { escapedCommand, commandId, rawOptions: { piped = false, ...options } }
|
|
6600
6875
|
}) => ({
|
|
6601
6876
|
type,
|
|
@@ -6603,7 +6878,7 @@ var getVerboseObject = ({
|
|
|
6603
6878
|
commandId: `${commandId}`,
|
|
6604
6879
|
timestamp: /* @__PURE__ */ new Date(),
|
|
6605
6880
|
piped,
|
|
6606
|
-
result,
|
|
6881
|
+
result: result2,
|
|
6607
6882
|
options
|
|
6608
6883
|
});
|
|
6609
6884
|
var getPrintedLines = (verboseMessage, verboseObject) => verboseMessage.split("\n").map((message) => getPrintedLine({ ...verboseObject, message }));
|
|
@@ -6732,28 +7007,28 @@ var npmRunPath = ({
|
|
|
6732
7007
|
addExecPath = true
|
|
6733
7008
|
} = {}) => {
|
|
6734
7009
|
const cwdPath = path2.resolve(toPath(cwd));
|
|
6735
|
-
const
|
|
7010
|
+
const result2 = [];
|
|
6736
7011
|
const pathParts = pathOption.split(path2.delimiter);
|
|
6737
7012
|
if (preferLocal) {
|
|
6738
|
-
applyPreferLocal(
|
|
7013
|
+
applyPreferLocal(result2, pathParts, cwdPath);
|
|
6739
7014
|
}
|
|
6740
7015
|
if (addExecPath) {
|
|
6741
|
-
applyExecPath(
|
|
7016
|
+
applyExecPath(result2, pathParts, execPath2, cwdPath);
|
|
6742
7017
|
}
|
|
6743
|
-
return pathOption === "" || pathOption === path2.delimiter ? `${
|
|
7018
|
+
return pathOption === "" || pathOption === path2.delimiter ? `${result2.join(path2.delimiter)}${pathOption}` : [...result2, pathOption].join(path2.delimiter);
|
|
6744
7019
|
};
|
|
6745
|
-
var applyPreferLocal = (
|
|
7020
|
+
var applyPreferLocal = (result2, pathParts, cwdPath) => {
|
|
6746
7021
|
for (const directory of traversePathUp(cwdPath)) {
|
|
6747
7022
|
const pathPart = path2.join(directory, "node_modules/.bin");
|
|
6748
7023
|
if (!pathParts.includes(pathPart)) {
|
|
6749
|
-
|
|
7024
|
+
result2.push(pathPart);
|
|
6750
7025
|
}
|
|
6751
7026
|
}
|
|
6752
7027
|
};
|
|
6753
|
-
var applyExecPath = (
|
|
7028
|
+
var applyExecPath = (result2, pathParts, execPath2, cwdPath) => {
|
|
6754
7029
|
const pathPart = path2.resolve(cwdPath, toPath(execPath2), "..");
|
|
6755
7030
|
if (!pathParts.includes(pathPart)) {
|
|
6756
|
-
|
|
7031
|
+
result2.push(pathPart);
|
|
6757
7032
|
}
|
|
6758
7033
|
};
|
|
6759
7034
|
var npmRunPathEnv = ({ env = process4.env, ...options } = {}) => {
|
|
@@ -8572,13 +8847,13 @@ var getMaxBufferInfo = (error, maxBuffer) => {
|
|
|
8572
8847
|
}
|
|
8573
8848
|
return { streamName: getStreamName(fdNumber), threshold, unit };
|
|
8574
8849
|
};
|
|
8575
|
-
var isMaxBufferSync = (resultError, output, maxBuffer) => resultError?.code === "ENOBUFS" && output !== null && output.some((
|
|
8576
|
-
var truncateMaxBufferSync = (
|
|
8850
|
+
var isMaxBufferSync = (resultError, output, maxBuffer) => resultError?.code === "ENOBUFS" && output !== null && output.some((result2) => result2 !== null && result2.length > getMaxBufferSync(maxBuffer));
|
|
8851
|
+
var truncateMaxBufferSync = (result2, isMaxBuffer, maxBuffer) => {
|
|
8577
8852
|
if (!isMaxBuffer) {
|
|
8578
|
-
return
|
|
8853
|
+
return result2;
|
|
8579
8854
|
}
|
|
8580
8855
|
const maxBufferValue = getMaxBufferSync(maxBuffer);
|
|
8581
|
-
return
|
|
8856
|
+
return result2.length > maxBufferValue ? result2.slice(0, maxBufferValue) : result2;
|
|
8582
8857
|
};
|
|
8583
8858
|
var getMaxBufferSync = ([, stdoutMaxBuffer]) => stdoutMaxBuffer;
|
|
8584
8859
|
|
|
@@ -8865,7 +9140,7 @@ var getErrorProperties = ({
|
|
|
8865
9140
|
ipcOutput,
|
|
8866
9141
|
pipedFrom: []
|
|
8867
9142
|
});
|
|
8868
|
-
var omitUndefinedProperties = (
|
|
9143
|
+
var omitUndefinedProperties = (result2) => Object.fromEntries(Object.entries(result2).filter(([, value]) => value !== void 0));
|
|
8869
9144
|
var normalizeExitPayload = (rawExitCode, rawSignal) => {
|
|
8870
9145
|
const exitCode = rawExitCode === null ? void 0 : rawExitCode;
|
|
8871
9146
|
const signal = rawSignal === null ? void 0 : rawSignal;
|
|
@@ -8936,25 +9211,25 @@ function prettyMilliseconds(milliseconds, options) {
|
|
|
8936
9211
|
options.secondsDecimalDigits = 0;
|
|
8937
9212
|
options.millisecondsDecimalDigits = 0;
|
|
8938
9213
|
}
|
|
8939
|
-
let
|
|
9214
|
+
let result2 = [];
|
|
8940
9215
|
const floorDecimals = (value, decimalDigits) => {
|
|
8941
9216
|
const flooredInterimValue = Math.floor(value * 10 ** decimalDigits + SECOND_ROUNDING_EPSILON);
|
|
8942
9217
|
const flooredValue = Math.round(flooredInterimValue) / 10 ** decimalDigits;
|
|
8943
9218
|
return flooredValue.toFixed(decimalDigits);
|
|
8944
9219
|
};
|
|
8945
9220
|
const add = (value, long, short, valueString) => {
|
|
8946
|
-
if ((
|
|
9221
|
+
if ((result2.length === 0 || !options.colonNotation) && isZero(value) && !(options.colonNotation && short === "m")) {
|
|
8947
9222
|
return;
|
|
8948
9223
|
}
|
|
8949
9224
|
valueString ??= String(value);
|
|
8950
9225
|
if (options.colonNotation) {
|
|
8951
9226
|
const wholeDigits = valueString.includes(".") ? valueString.split(".")[0].length : valueString.length;
|
|
8952
|
-
const minLength =
|
|
9227
|
+
const minLength = result2.length > 0 ? 2 : 1;
|
|
8953
9228
|
valueString = "0".repeat(Math.max(0, minLength - wholeDigits)) + valueString;
|
|
8954
9229
|
} else {
|
|
8955
9230
|
valueString += options.verbose ? " " + pluralize(long, value) : short;
|
|
8956
9231
|
}
|
|
8957
|
-
|
|
9232
|
+
result2.push(valueString);
|
|
8958
9233
|
};
|
|
8959
9234
|
const parsed = parseMilliseconds(milliseconds);
|
|
8960
9235
|
const days = BigInt(parsed.days);
|
|
@@ -9001,53 +9276,53 @@ function prettyMilliseconds(milliseconds, options) {
|
|
|
9001
9276
|
add(Number.parseFloat(secondsString), "second", "s", secondsString);
|
|
9002
9277
|
}
|
|
9003
9278
|
}
|
|
9004
|
-
if (
|
|
9279
|
+
if (result2.length === 0) {
|
|
9005
9280
|
return sign + "0" + (options.verbose ? " milliseconds" : "ms");
|
|
9006
9281
|
}
|
|
9007
9282
|
const separator = options.colonNotation ? ":" : " ";
|
|
9008
9283
|
if (typeof options.unitCount === "number") {
|
|
9009
|
-
|
|
9284
|
+
result2 = result2.slice(0, Math.max(options.unitCount, 1));
|
|
9010
9285
|
}
|
|
9011
|
-
return sign +
|
|
9286
|
+
return sign + result2.join(separator);
|
|
9012
9287
|
}
|
|
9013
9288
|
|
|
9014
9289
|
// ../../node_modules/.pnpm/execa@9.6.1/node_modules/execa/lib/verbose/error.js
|
|
9015
|
-
var logError = (
|
|
9016
|
-
if (
|
|
9290
|
+
var logError = (result2, verboseInfo) => {
|
|
9291
|
+
if (result2.failed) {
|
|
9017
9292
|
verboseLog({
|
|
9018
9293
|
type: "error",
|
|
9019
|
-
verboseMessage:
|
|
9294
|
+
verboseMessage: result2.shortMessage,
|
|
9020
9295
|
verboseInfo,
|
|
9021
|
-
result
|
|
9296
|
+
result: result2
|
|
9022
9297
|
});
|
|
9023
9298
|
}
|
|
9024
9299
|
};
|
|
9025
9300
|
|
|
9026
9301
|
// ../../node_modules/.pnpm/execa@9.6.1/node_modules/execa/lib/verbose/complete.js
|
|
9027
|
-
var logResult = (
|
|
9302
|
+
var logResult = (result2, verboseInfo) => {
|
|
9028
9303
|
if (!isVerbose(verboseInfo)) {
|
|
9029
9304
|
return;
|
|
9030
9305
|
}
|
|
9031
|
-
logError(
|
|
9032
|
-
logDuration(
|
|
9306
|
+
logError(result2, verboseInfo);
|
|
9307
|
+
logDuration(result2, verboseInfo);
|
|
9033
9308
|
};
|
|
9034
|
-
var logDuration = (
|
|
9035
|
-
const verboseMessage = `(done in ${prettyMilliseconds(
|
|
9309
|
+
var logDuration = (result2, verboseInfo) => {
|
|
9310
|
+
const verboseMessage = `(done in ${prettyMilliseconds(result2.durationMs)})`;
|
|
9036
9311
|
verboseLog({
|
|
9037
9312
|
type: "duration",
|
|
9038
9313
|
verboseMessage,
|
|
9039
9314
|
verboseInfo,
|
|
9040
|
-
result
|
|
9315
|
+
result: result2
|
|
9041
9316
|
});
|
|
9042
9317
|
};
|
|
9043
9318
|
|
|
9044
9319
|
// ../../node_modules/.pnpm/execa@9.6.1/node_modules/execa/lib/return/reject.js
|
|
9045
|
-
var handleResult = (
|
|
9046
|
-
logResult(
|
|
9047
|
-
if (
|
|
9048
|
-
throw
|
|
9320
|
+
var handleResult = (result2, verboseInfo, { reject }) => {
|
|
9321
|
+
logResult(result2, verboseInfo);
|
|
9322
|
+
if (result2.failed && reject) {
|
|
9323
|
+
throw result2;
|
|
9049
9324
|
}
|
|
9050
|
-
return
|
|
9325
|
+
return result2;
|
|
9051
9326
|
};
|
|
9052
9327
|
|
|
9053
9328
|
// ../../node_modules/.pnpm/execa@9.6.1/node_modules/execa/lib/stdio/handle-sync.js
|
|
@@ -10131,8 +10406,8 @@ var transformOutputSync = ({ fileDescriptors, syncResult: { output }, options, i
|
|
|
10131
10406
|
}
|
|
10132
10407
|
const state = {};
|
|
10133
10408
|
const outputFiles = /* @__PURE__ */ new Set([]);
|
|
10134
|
-
const transformedOutput = output.map((
|
|
10135
|
-
result,
|
|
10409
|
+
const transformedOutput = output.map((result2, fdNumber) => transformOutputResultSync({
|
|
10410
|
+
result: result2,
|
|
10136
10411
|
fileDescriptors,
|
|
10137
10412
|
fdNumber,
|
|
10138
10413
|
state,
|
|
@@ -10142,11 +10417,11 @@ var transformOutputSync = ({ fileDescriptors, syncResult: { output }, options, i
|
|
|
10142
10417
|
}, options));
|
|
10143
10418
|
return { output: transformedOutput, ...state };
|
|
10144
10419
|
};
|
|
10145
|
-
var transformOutputResultSync = ({ result, fileDescriptors, fdNumber, state, outputFiles, isMaxBuffer, verboseInfo }, { buffer, encoding, lines, stripFinalNewline: stripFinalNewline2, maxBuffer }) => {
|
|
10146
|
-
if (
|
|
10420
|
+
var transformOutputResultSync = ({ result: result2, fileDescriptors, fdNumber, state, outputFiles, isMaxBuffer, verboseInfo }, { buffer, encoding, lines, stripFinalNewline: stripFinalNewline2, maxBuffer }) => {
|
|
10421
|
+
if (result2 === null) {
|
|
10147
10422
|
return;
|
|
10148
10423
|
}
|
|
10149
|
-
const truncatedResult = truncateMaxBufferSync(
|
|
10424
|
+
const truncatedResult = truncateMaxBufferSync(result2, isMaxBuffer, maxBuffer);
|
|
10150
10425
|
const uint8ArrayResult = bufferToUint8Array(truncatedResult);
|
|
10151
10426
|
const { stdioItems, objectMode } = fileDescriptors[fdNumber];
|
|
10152
10427
|
const chunks = runOutputGeneratorsSync([uint8ArrayResult], stdioItems, encoding, state);
|
|
@@ -10307,7 +10582,7 @@ var getResultError = (error, exitCode, signal) => {
|
|
|
10307
10582
|
// ../../node_modules/.pnpm/execa@9.6.1/node_modules/execa/lib/methods/main-sync.js
|
|
10308
10583
|
var execaCoreSync = (rawFile, rawArguments, rawOptions) => {
|
|
10309
10584
|
const { file, commandArguments, command, escapedCommand, startTime, verboseInfo, options, fileDescriptors } = handleSyncArguments(rawFile, rawArguments, rawOptions);
|
|
10310
|
-
const
|
|
10585
|
+
const result2 = spawnSubprocessSync({
|
|
10311
10586
|
file,
|
|
10312
10587
|
commandArguments,
|
|
10313
10588
|
options,
|
|
@@ -10317,7 +10592,7 @@ var execaCoreSync = (rawFile, rawArguments, rawOptions) => {
|
|
|
10317
10592
|
fileDescriptors,
|
|
10318
10593
|
startTime
|
|
10319
10594
|
});
|
|
10320
|
-
return handleResult(
|
|
10595
|
+
return handleResult(result2, verboseInfo, options);
|
|
10321
10596
|
};
|
|
10322
10597
|
var handleSyncArguments = (rawFile, rawArguments, rawOptions) => {
|
|
10323
10598
|
const { command, escapedCommand, startTime, verboseInfo } = handleCommand(rawFile, rawArguments, rawOptions);
|
|
@@ -12453,7 +12728,7 @@ var handlePromise = async ({ subprocess, options, startTime, verboseInfo, fileDe
|
|
|
12453
12728
|
onInternalError.resolve();
|
|
12454
12729
|
const stdio = stdioResults.map((stdioResult, fdNumber) => stripNewline(stdioResult, options, fdNumber));
|
|
12455
12730
|
const all = stripNewline(allResult, options, "all");
|
|
12456
|
-
const
|
|
12731
|
+
const result2 = getAsyncResult({
|
|
12457
12732
|
errorInfo,
|
|
12458
12733
|
exitCode,
|
|
12459
12734
|
signal,
|
|
@@ -12466,7 +12741,7 @@ var handlePromise = async ({ subprocess, options, startTime, verboseInfo, fileDe
|
|
|
12466
12741
|
escapedCommand,
|
|
12467
12742
|
startTime
|
|
12468
12743
|
});
|
|
12469
|
-
return handleResult(
|
|
12744
|
+
return handleResult(result2, verboseInfo, options);
|
|
12470
12745
|
};
|
|
12471
12746
|
var getAsyncResult = ({ errorInfo, exitCode, signal, stdio, all, ipcOutput, context, options, command, escapedCommand, startTime }) => "error" in errorInfo ? makeError({
|
|
12472
12747
|
error: errorInfo.error,
|
|
@@ -12664,28 +12939,28 @@ async function executeShellCommand(command, cwd, channel) {
|
|
|
12664
12939
|
kind: "command",
|
|
12665
12940
|
text: `\u6267\u884C\u547D\u4EE4\uFF1A${truncate(command, 120)}`
|
|
12666
12941
|
});
|
|
12667
|
-
const
|
|
12942
|
+
const result2 = await child;
|
|
12668
12943
|
const output = [
|
|
12669
|
-
|
|
12670
|
-
|
|
12671
|
-
`[Exit code: ${
|
|
12944
|
+
result2.all?.trim() || "",
|
|
12945
|
+
result2.timedOut ? "[Timed out after 60s]" : "",
|
|
12946
|
+
`[Exit code: ${result2.exitCode ?? "killed"}]`
|
|
12672
12947
|
].filter(Boolean).join("\n");
|
|
12673
12948
|
runningProcesses.delete(pid);
|
|
12674
12949
|
execaProcesses.delete(pid);
|
|
12675
12950
|
queueDigest(shellSessionId, {
|
|
12676
12951
|
kind: "command",
|
|
12677
|
-
text: `\u547D\u4EE4\u7ED3\u675F\uFF1A\u9000\u51FA\u7801 ${
|
|
12952
|
+
text: `\u547D\u4EE4\u7ED3\u675F\uFF1A\u9000\u51FA\u7801 ${result2.exitCode ?? "killed"}`
|
|
12678
12953
|
});
|
|
12679
12954
|
await flushDigest(shellSessionId);
|
|
12680
12955
|
await handleResultEvent(
|
|
12681
12956
|
shellSessionId,
|
|
12682
12957
|
{
|
|
12683
12958
|
type: "result",
|
|
12684
|
-
success:
|
|
12959
|
+
success: result2.exitCode === 0,
|
|
12685
12960
|
costUsd: 0,
|
|
12686
12961
|
durationMs: Date.now() - shellProcess.startedAt,
|
|
12687
12962
|
numTurns: 1,
|
|
12688
|
-
errors:
|
|
12963
|
+
errors: result2.exitCode === 0 ? [] : [output],
|
|
12689
12964
|
metadata: { sessionEnd: false }
|
|
12690
12965
|
},
|
|
12691
12966
|
renderShellOutput(command, output)
|
|
@@ -12774,9 +13049,6 @@ async function handleShellKill(interaction) {
|
|
|
12774
13049
|
});
|
|
12775
13050
|
}
|
|
12776
13051
|
|
|
12777
|
-
// ../bot/src/button-handler.ts
|
|
12778
|
-
import "discord.js";
|
|
12779
|
-
|
|
12780
13052
|
// ../bot/src/button-handler-actions.ts
|
|
12781
13053
|
import {
|
|
12782
13054
|
ActionRowBuilder as ActionRowBuilder3,
|
|
@@ -12786,12 +13058,11 @@ function asComponentLike(component) {
|
|
|
12786
13058
|
return component || {};
|
|
12787
13059
|
}
|
|
12788
13060
|
async function resolveAwaitingHumanIfNeeded(sessionId) {
|
|
12789
|
-
const session =
|
|
13061
|
+
const session = getSessionView(sessionId);
|
|
12790
13062
|
if (!session?.currentInteractionMessageId) {
|
|
12791
13063
|
return;
|
|
12792
13064
|
}
|
|
12793
13065
|
updateSession(sessionId, {
|
|
12794
|
-
humanResolved: true,
|
|
12795
13066
|
currentInteractionMessageId: void 0
|
|
12796
13067
|
});
|
|
12797
13068
|
await updateSessionState(sessionId, {
|
|
@@ -12803,19 +13074,19 @@ async function resolveAwaitingHumanIfNeeded(sessionId) {
|
|
|
12803
13074
|
metadata: { source: "answer" }
|
|
12804
13075
|
});
|
|
12805
13076
|
}
|
|
12806
|
-
function renderCleanupResultMessage(
|
|
13077
|
+
function renderCleanupResultMessage(result2) {
|
|
12807
13078
|
const lines = [
|
|
12808
13079
|
"\u6279\u91CF\u6E05\u7406\u5B8C\u6210",
|
|
12809
13080
|
"",
|
|
12810
|
-
`- \u5DF2\u5F52\u6863\uFF1A${
|
|
12811
|
-
`- \u8DF3\u8FC7\u8FDB\u884C\u4E2D\uFF1A${
|
|
12812
|
-
`- \u7F3A\u5931\uFF1A${
|
|
12813
|
-
`- \u5931\u8D25\uFF1A${
|
|
13081
|
+
`- \u5DF2\u5F52\u6863\uFF1A${result2.archivedSessions}`,
|
|
13082
|
+
`- \u8DF3\u8FC7\u8FDB\u884C\u4E2D\uFF1A${result2.skippedGenerating}`,
|
|
13083
|
+
`- \u7F3A\u5931\uFF1A${result2.missingSessions}`,
|
|
13084
|
+
`- \u5931\u8D25\uFF1A${result2.failed.length}`
|
|
12814
13085
|
];
|
|
12815
|
-
if (
|
|
13086
|
+
if (result2.failed.length > 0) {
|
|
12816
13087
|
lines.push("", "\u5931\u8D25\u660E\u7EC6\uFF1A");
|
|
12817
13088
|
lines.push(
|
|
12818
|
-
...
|
|
13089
|
+
...result2.failed.map((item) => `- ${item.channelId ? `<#${item.channelId}> ` : ""}${item.sessionId}\uFF1A${item.message}`)
|
|
12819
13090
|
);
|
|
12820
13091
|
}
|
|
12821
13092
|
return lines.join("\n");
|
|
@@ -12838,7 +13109,7 @@ async function handleAwaitingHumanButton(interaction) {
|
|
|
12838
13109
|
const sessionId = parts[1];
|
|
12839
13110
|
const turn = parseInt(parts[2], 10);
|
|
12840
13111
|
const action = parts[3];
|
|
12841
|
-
const session =
|
|
13112
|
+
const session = getSessionView(sessionId);
|
|
12842
13113
|
if (!session) {
|
|
12843
13114
|
await interaction.reply({ content: "\u4F1A\u8BDD\u4E0D\u5B58\u5728", ephemeral: true });
|
|
12844
13115
|
return true;
|
|
@@ -12856,24 +13127,24 @@ async function handleAwaitingHumanButton(interaction) {
|
|
|
12856
13127
|
await interaction.reply({ content: "\u5DF2\u88AB\u5176\u4ED6\u4EBA\u5904\u7406", ephemeral: true });
|
|
12857
13128
|
return true;
|
|
12858
13129
|
}
|
|
12859
|
-
const activeGate = session.activeHumanGateId ?
|
|
13130
|
+
const activeGate = session.activeHumanGateId ? gateService.getGate(session.activeHumanGateId) : gateService.getActiveGateForSession(sessionId);
|
|
12860
13131
|
if (!activeGate) {
|
|
12861
13132
|
await interaction.reply({ content: "\u672A\u627E\u5230\u6D3B\u8DC3\u7684\u95E8\u63A7\u8BB0\u5F55", ephemeral: true });
|
|
12862
13133
|
return true;
|
|
12863
13134
|
}
|
|
12864
|
-
const
|
|
13135
|
+
const result2 = await gateService.resolveFromDiscord(
|
|
12865
13136
|
activeGate.id,
|
|
12866
13137
|
action === "approve" ? "approve" : "reject"
|
|
12867
13138
|
);
|
|
12868
|
-
if (!
|
|
13139
|
+
if (!result2.success) {
|
|
12869
13140
|
await interaction.reply({
|
|
12870
|
-
content: `\u5904\u7406\u5931\u8D25: ${
|
|
13141
|
+
content: `\u5904\u7406\u5931\u8D25: ${result2.message || "\u672A\u77E5\u9519\u8BEF"}`,
|
|
12871
13142
|
ephemeral: true
|
|
12872
13143
|
});
|
|
12873
13144
|
return true;
|
|
12874
13145
|
}
|
|
13146
|
+
stateMachine.setHumanResolved(sessionId, true);
|
|
12875
13147
|
updateSession(sessionId, {
|
|
12876
|
-
humanResolved: true,
|
|
12877
13148
|
currentInteractionMessageId: void 0,
|
|
12878
13149
|
activeHumanGateId: void 0
|
|
12879
13150
|
});
|
|
@@ -12886,7 +13157,7 @@ async function handleAwaitingHumanButton(interaction) {
|
|
|
12886
13157
|
}
|
|
12887
13158
|
}))
|
|
12888
13159
|
});
|
|
12889
|
-
if (
|
|
13160
|
+
if (result2.handledByReceipt) {
|
|
12890
13161
|
return true;
|
|
12891
13162
|
}
|
|
12892
13163
|
if (action === "approve") {
|
|
@@ -12929,7 +13200,7 @@ async function handleContinueButton(interaction) {
|
|
|
12929
13200
|
const customId = interaction.customId;
|
|
12930
13201
|
if (!customId.startsWith("continue:")) return false;
|
|
12931
13202
|
const sessionId = customId.slice(9);
|
|
12932
|
-
const session =
|
|
13203
|
+
const session = getSessionView(sessionId);
|
|
12933
13204
|
if (!session) {
|
|
12934
13205
|
await interaction.reply({ content: "\u4F1A\u8BDD\u4E0D\u5B58\u5728\u3002", ephemeral: true });
|
|
12935
13206
|
return true;
|
|
@@ -13016,13 +13287,13 @@ async function handleCleanupButtons(interaction) {
|
|
|
13016
13287
|
await interaction.deferUpdate();
|
|
13017
13288
|
try {
|
|
13018
13289
|
console.log(`[ButtonHandler] Cleanup confirmed by ${interaction.user.tag} \u2014 archiving ${request.candidateSessionIds.length} sessions`);
|
|
13019
|
-
const
|
|
13290
|
+
const result2 = await archiveSessionsById(
|
|
13020
13291
|
interaction.guild,
|
|
13021
13292
|
request.candidateSessionIds,
|
|
13022
13293
|
"Bulk cleanup from Discord command"
|
|
13023
13294
|
);
|
|
13024
13295
|
deleteCleanupRequest(requestId);
|
|
13025
|
-
await interaction.editReply({ content: renderCleanupResultMessage(
|
|
13296
|
+
await interaction.editReply({ content: renderCleanupResultMessage(result2), components: [] });
|
|
13026
13297
|
} finally {
|
|
13027
13298
|
releaseCleanupLock(request.categoryId);
|
|
13028
13299
|
}
|
|
@@ -13036,7 +13307,7 @@ async function handleModeButton(interaction) {
|
|
|
13036
13307
|
const parts = customId.split(":");
|
|
13037
13308
|
const sessionId = parts[1];
|
|
13038
13309
|
const newMode = parts[2];
|
|
13039
|
-
const session =
|
|
13310
|
+
const session = getSessionView(sessionId);
|
|
13040
13311
|
if (!session) {
|
|
13041
13312
|
await interaction.reply({ content: "\u4F1A\u8BDD\u4E0D\u5B58\u5728\u3002", ephemeral: true });
|
|
13042
13313
|
return true;
|
|
@@ -13053,7 +13324,7 @@ async function handleModeButton(interaction) {
|
|
|
13053
13324
|
await interaction.reply({ content: `\u5DF2\u5207\u6362\u81F3 **${labels[newMode]}**`, ephemeral: true });
|
|
13054
13325
|
try {
|
|
13055
13326
|
const original = interaction.message;
|
|
13056
|
-
const liveSession =
|
|
13327
|
+
const liveSession = getSessionView(sessionId);
|
|
13057
13328
|
const updatedComponents = original.components.map((row) => {
|
|
13058
13329
|
if (!("components" in row)) return row;
|
|
13059
13330
|
const first = asComponentLike(row.components?.[0]);
|
|
@@ -13074,7 +13345,7 @@ async function handleSelectMenuAction(interaction) {
|
|
|
13074
13345
|
const sessionId = parts[1];
|
|
13075
13346
|
const questionIndex = parseInt(parts[2], 10);
|
|
13076
13347
|
const selected = interaction.values[0];
|
|
13077
|
-
const session =
|
|
13348
|
+
const session = getSessionView(sessionId);
|
|
13078
13349
|
if (!session) {
|
|
13079
13350
|
await interaction.reply({ content: "\u4F1A\u8BDD\u4E0D\u5B58\u5728\u3002", ephemeral: true });
|
|
13080
13351
|
return true;
|
|
@@ -13113,7 +13384,7 @@ async function handleSelectMenuAction(interaction) {
|
|
|
13113
13384
|
const afterPrefix = customId.slice(14);
|
|
13114
13385
|
const sessionId = afterPrefix.includes(":") ? afterPrefix.split(":")[0] : afterPrefix;
|
|
13115
13386
|
const selected = interaction.values[0];
|
|
13116
|
-
const session =
|
|
13387
|
+
const session = getSessionView(sessionId);
|
|
13117
13388
|
if (!session) {
|
|
13118
13389
|
await interaction.reply({ content: "\u4F1A\u8BDD\u4E0D\u5B58\u5728\u3002", ephemeral: true });
|
|
13119
13390
|
return true;
|
|
@@ -13132,7 +13403,7 @@ async function handleSelectMenuAction(interaction) {
|
|
|
13132
13403
|
if (customId.startsWith("select:")) {
|
|
13133
13404
|
const sessionId = customId.slice(7);
|
|
13134
13405
|
const selected = interaction.values[0];
|
|
13135
|
-
const session =
|
|
13406
|
+
const session = getSessionView(sessionId);
|
|
13136
13407
|
if (!session) {
|
|
13137
13408
|
await interaction.reply({ content: "\u4F1A\u8BDD\u4E0D\u5B58\u5728\u3002", ephemeral: true });
|
|
13138
13409
|
return true;
|
|
@@ -13151,31 +13422,58 @@ async function handleSelectMenuAction(interaction) {
|
|
|
13151
13422
|
return false;
|
|
13152
13423
|
}
|
|
13153
13424
|
|
|
13154
|
-
// ../bot/src/button-
|
|
13155
|
-
|
|
13156
|
-
|
|
13157
|
-
|
|
13158
|
-
|
|
13425
|
+
// ../bot/src/button-router.ts
|
|
13426
|
+
var BUTTON_ROUTES = [
|
|
13427
|
+
handleStopButton,
|
|
13428
|
+
handleAwaitingHumanButton,
|
|
13429
|
+
handleContinueButton,
|
|
13430
|
+
handleExpandButton,
|
|
13431
|
+
handleDeprecatedInteractionButton,
|
|
13432
|
+
handleCleanupButtons,
|
|
13433
|
+
handleModeButton
|
|
13434
|
+
];
|
|
13435
|
+
var SELECT_ROUTES = [handleSelectMenuAction];
|
|
13436
|
+
async function checkAuthorization(userId, reply) {
|
|
13437
|
+
if (isUserAllowed(userId, config.allowedUsers, config.allowAllUsers)) return true;
|
|
13438
|
+
await reply("\u672A\u6388\u6743\u3002");
|
|
13439
|
+
return false;
|
|
13440
|
+
}
|
|
13441
|
+
async function routeButton(interaction) {
|
|
13442
|
+
const ok = await checkAuthorization(
|
|
13443
|
+
interaction.user.id,
|
|
13444
|
+
(content) => interaction.reply({ content, ephemeral: true })
|
|
13445
|
+
);
|
|
13446
|
+
if (!ok) {
|
|
13447
|
+
console.warn(
|
|
13448
|
+
`[ButtonHandler] Unauthorized button press by user ${interaction.user.id}: ${interaction.customId}`
|
|
13449
|
+
);
|
|
13159
13450
|
return;
|
|
13160
13451
|
}
|
|
13161
|
-
|
|
13162
|
-
|
|
13163
|
-
|
|
13164
|
-
if (await handleExpandButton(interaction)) return;
|
|
13165
|
-
if (await handleDeprecatedInteractionButton(interaction)) return;
|
|
13166
|
-
if (await handleCleanupButtons(interaction)) return;
|
|
13167
|
-
if (await handleModeButton(interaction)) return;
|
|
13452
|
+
for (const route of BUTTON_ROUTES) {
|
|
13453
|
+
if (await route(interaction)) return;
|
|
13454
|
+
}
|
|
13168
13455
|
await interaction.reply({ content: "\u672A\u77E5\u6309\u94AE\u3002", ephemeral: true });
|
|
13169
13456
|
}
|
|
13170
|
-
async function
|
|
13171
|
-
|
|
13172
|
-
|
|
13173
|
-
|
|
13457
|
+
async function routeSelectMenu(interaction) {
|
|
13458
|
+
const ok = await checkAuthorization(
|
|
13459
|
+
interaction.user.id,
|
|
13460
|
+
(content) => interaction.reply({ content, ephemeral: true })
|
|
13461
|
+
);
|
|
13462
|
+
if (!ok) return;
|
|
13463
|
+
for (const route of SELECT_ROUTES) {
|
|
13464
|
+
if (await route(interaction)) return;
|
|
13174
13465
|
}
|
|
13175
|
-
if (await handleSelectMenuAction(interaction)) return;
|
|
13176
13466
|
await interaction.reply({ content: "\u672A\u77E5\u9009\u62E9\u3002", ephemeral: true });
|
|
13177
13467
|
}
|
|
13178
13468
|
|
|
13469
|
+
// ../bot/src/button-handler.ts
|
|
13470
|
+
async function handleButton(interaction) {
|
|
13471
|
+
await routeButton(interaction);
|
|
13472
|
+
}
|
|
13473
|
+
async function handleSelectMenu(interaction) {
|
|
13474
|
+
await routeSelectMenu(interaction);
|
|
13475
|
+
}
|
|
13476
|
+
|
|
13179
13477
|
// ../bot/src/bot-event-router.ts
|
|
13180
13478
|
import {
|
|
13181
13479
|
InteractionType
|
|
@@ -13356,7 +13654,7 @@ async function runCli() {
|
|
|
13356
13654
|
await startBot();
|
|
13357
13655
|
});
|
|
13358
13656
|
cli.command("config [action] [key] [value]", "Manage configuration").action(async (action, key, value) => {
|
|
13359
|
-
const { handleConfig } = await import("./config-cli-
|
|
13657
|
+
const { handleConfig } = await import("./config-cli-7JEV3WYY.js");
|
|
13360
13658
|
const args = [action || "list"].filter(Boolean);
|
|
13361
13659
|
if (key) args.push(key);
|
|
13362
13660
|
if (value) args.push(value);
|
|
@@ -13364,12 +13662,12 @@ async function runCli() {
|
|
|
13364
13662
|
await handleConfig(args);
|
|
13365
13663
|
});
|
|
13366
13664
|
cli.command("project [action] [...args]", "Manage mounted projects").action(async (action, args) => {
|
|
13367
|
-
const { handleProject: handleProject2 } = await import("./project-cli-
|
|
13665
|
+
const { handleProject: handleProject2 } = await import("./project-cli-ZXMHOFUJ.js");
|
|
13368
13666
|
const cmdArgs = [action || "help"].filter(Boolean).concat(args || []);
|
|
13369
13667
|
await handleProject2(cmdArgs);
|
|
13370
13668
|
});
|
|
13371
13669
|
cli.command("attachment [action]", "Manage attachments").action(async (action) => {
|
|
13372
|
-
const { handleAttachment } = await import("./attachment-cli-
|
|
13670
|
+
const { handleAttachment } = await import("./attachment-cli-MF7XZ4WT.js");
|
|
13373
13671
|
await handleAttachment([action || "fetch"]);
|
|
13374
13672
|
});
|
|
13375
13673
|
cli.command("daemon <action>", "Manage background service").action(async (action) => {
|
|
@@ -13377,7 +13675,7 @@ async function runCli() {
|
|
|
13377
13675
|
await handleDaemon(action);
|
|
13378
13676
|
});
|
|
13379
13677
|
cli.command("codex [...options]", "Launch managed Codex session with remote approval").allowUnknownOptions().action(async function(options) {
|
|
13380
|
-
const { handleCodexCommand } = await import("./codex-launcher-
|
|
13678
|
+
const { handleCodexCommand } = await import("./codex-launcher-ZBQ5VL6L.js");
|
|
13381
13679
|
const parsed = this.options;
|
|
13382
13680
|
const rawArgs = [];
|
|
13383
13681
|
for (const [key, value] of Object.entries(parsed)) {
|