@triflux/core 10.87.0 → 10.88.1
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/hub/bridge.mjs +411 -5
- package/hub/lib/jev-addon.mjs +1675 -0
- package/hub/team/pane.mjs +99 -0
- package/hub/team/retry-state-machine.mjs +22 -2
- package/hud/hud-qos-status.mjs +45 -16
- package/hud/renderers.mjs +13 -3
- package/hud/session-status.mjs +46 -0
- package/hud/tmux-status.mjs +140 -0
- package/package.json +1 -1
- package/scripts/lib/doctor-env-checks.mjs +377 -0
- package/scripts/lib/mcp-filter.mjs +86 -3
package/hub/bridge.mjs
CHANGED
|
@@ -3,7 +3,17 @@
|
|
|
3
3
|
// hub/bridge.mjs: tfx-route.sh 와 tfx-live 가 부르는 로컬 제어 CLI.
|
|
4
4
|
// 팀 하위 명령은 nativeProxy 를 직접 호출하고 Claude daemon, retry, intervene 은 로컬 모듈만 쓴다.
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
closeSync,
|
|
8
|
+
existsSync,
|
|
9
|
+
fstatSync,
|
|
10
|
+
openSync,
|
|
11
|
+
readFileSync,
|
|
12
|
+
readSync,
|
|
13
|
+
writeFileSync,
|
|
14
|
+
} from "node:fs";
|
|
15
|
+
import { tmpdir } from "node:os";
|
|
16
|
+
import { join } from "node:path";
|
|
7
17
|
import { parseArgs as nodeParseArgs } from "node:util";
|
|
8
18
|
|
|
9
19
|
import {
|
|
@@ -46,6 +56,17 @@ export function parseArgs(argv) {
|
|
|
46
56
|
"snapshot-file": { type: "string" },
|
|
47
57
|
event: { type: "string" },
|
|
48
58
|
"max-iterations": { type: "string" },
|
|
59
|
+
"stdout-log": { type: "string" },
|
|
60
|
+
"stderr-log": { type: "string" },
|
|
61
|
+
"rollout-file": { type: "string" },
|
|
62
|
+
"elapsed-sec": { type: "string" },
|
|
63
|
+
"result-file": { type: "string" },
|
|
64
|
+
agent: { type: "string" },
|
|
65
|
+
"cli-type": { type: "string" },
|
|
66
|
+
"available-servers": { type: "string" },
|
|
67
|
+
prompt: { type: "string" },
|
|
68
|
+
instruction: { type: "string" },
|
|
69
|
+
delimited: { type: "boolean" },
|
|
49
70
|
},
|
|
50
71
|
allowPositionals: true,
|
|
51
72
|
strict: false,
|
|
@@ -151,14 +172,35 @@ async function cmdTeamTaskUpdate(args) {
|
|
|
151
172
|
|
|
152
173
|
async function cmdTeamSendMessage(args) {
|
|
153
174
|
const { teamSendMessage } = await import("./team/nativeProxy.mjs");
|
|
175
|
+
const { isJevEnabled, judgeInboxPriority } = await import(
|
|
176
|
+
"./lib/jev-addon.mjs"
|
|
177
|
+
);
|
|
178
|
+
let summary = args.summary;
|
|
179
|
+
let priority = null;
|
|
180
|
+
let urgencyScore = null;
|
|
181
|
+
if (isJevEnabled()) {
|
|
182
|
+
const verdict = await judgeInboxPriority({
|
|
183
|
+
text: args.text,
|
|
184
|
+
summary: args.summary,
|
|
185
|
+
from: args.from,
|
|
186
|
+
});
|
|
187
|
+
if (verdict) {
|
|
188
|
+
priority = verdict.priority;
|
|
189
|
+
urgencyScore = verdict.urgencyScore;
|
|
190
|
+
if (summary && !String(summary).startsWith("[JEV:")) {
|
|
191
|
+
summary = `[JEV:${verdict.priority}] ${summary}`;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
154
195
|
return emitJson(
|
|
155
196
|
await teamSendMessage({
|
|
156
197
|
team_name: args.team,
|
|
157
198
|
from: args.from,
|
|
158
199
|
to: args.to || "team-lead",
|
|
159
200
|
text: args.text,
|
|
160
|
-
summary
|
|
201
|
+
summary,
|
|
161
202
|
color: args.color || "blue",
|
|
203
|
+
...(priority ? { priority, urgencyScore } : {}),
|
|
162
204
|
}),
|
|
163
205
|
);
|
|
164
206
|
}
|
|
@@ -706,7 +748,7 @@ async function cmdRetryRun(args) {
|
|
|
706
748
|
result = sm.reportVerifySuccess();
|
|
707
749
|
break;
|
|
708
750
|
case "verify-fail":
|
|
709
|
-
result = sm.
|
|
751
|
+
result = await sm.reportVerifyFailAsync(reason || "unspecified");
|
|
710
752
|
break;
|
|
711
753
|
default:
|
|
712
754
|
console.error(`unknown --event: ${event}`);
|
|
@@ -781,6 +823,7 @@ async function cmdInterveneRun(args) {
|
|
|
781
823
|
codexHome: payload.codexHome,
|
|
782
824
|
});
|
|
783
825
|
}
|
|
826
|
+
let reinstructPrompt = payload.reinstructPrompt || undefined;
|
|
784
827
|
const seconds = (value) => {
|
|
785
828
|
const parsed = numericOption(value, undefined);
|
|
786
829
|
return parsed > 0 ? parsed * 1_000 : undefined;
|
|
@@ -791,6 +834,54 @@ async function cmdInterveneRun(args) {
|
|
|
791
834
|
),
|
|
792
835
|
rolloutFile,
|
|
793
836
|
});
|
|
837
|
+
const { isJevEnabled, judgeWorkerHealth } = await import(
|
|
838
|
+
"./lib/jev-addon.mjs"
|
|
839
|
+
);
|
|
840
|
+
if (isJevEnabled() && payload.skipJevHealthCheck !== true) {
|
|
841
|
+
const stdoutTail = readTailSafe(payload.stdoutLog);
|
|
842
|
+
const stderrTail = readTailSafe(payload.stderrLog);
|
|
843
|
+
const rolloutTail = readTailSafe(rolloutFile);
|
|
844
|
+
const activitySig = await Promise.resolve(readActivitySignature()).catch(
|
|
845
|
+
() => "",
|
|
846
|
+
);
|
|
847
|
+
const graceTargetKey = String(
|
|
848
|
+
payload.pid ||
|
|
849
|
+
payload.paneId ||
|
|
850
|
+
payload.sessionId ||
|
|
851
|
+
payload.stdoutLog ||
|
|
852
|
+
payload.stderrLog ||
|
|
853
|
+
rolloutFile ||
|
|
854
|
+
"default",
|
|
855
|
+
);
|
|
856
|
+
const logSignature = `${activitySig}|${stdoutTail.length}:${stderrTail.length}:${rolloutTail.length}|${stdoutTail.slice(-160)}|${stderrTail.slice(-160)}|${rolloutTail.slice(-160)}`;
|
|
857
|
+
const alreadyGranted = hasGrantedProgressingGrace(
|
|
858
|
+
graceTargetKey,
|
|
859
|
+
logSignature,
|
|
860
|
+
);
|
|
861
|
+
const verdict = await judgeWorkerHealth({
|
|
862
|
+
stdoutTail,
|
|
863
|
+
stderrTail,
|
|
864
|
+
rolloutTail,
|
|
865
|
+
elapsedSec: numericOption(payload.elapsedSec, 0),
|
|
866
|
+
});
|
|
867
|
+
if (verdict?.status === "progressing" && !alreadyGranted) {
|
|
868
|
+
recordProgressingGrace(graceTargetKey, logSignature);
|
|
869
|
+
return emitJson({
|
|
870
|
+
ok: true,
|
|
871
|
+
outcome: "recovered",
|
|
872
|
+
step: "jev-health-check",
|
|
873
|
+
status: "progressing",
|
|
874
|
+
confidence: verdict.confidence,
|
|
875
|
+
});
|
|
876
|
+
}
|
|
877
|
+
if (!reinstructPrompt && verdict?.status === "waiting_input") {
|
|
878
|
+
reinstructPrompt =
|
|
879
|
+
"Continue non-interactively using safe defaults without waiting for interactive user input.";
|
|
880
|
+
} else if (!reinstructPrompt && verdict?.status === "looping_error") {
|
|
881
|
+
reinstructPrompt =
|
|
882
|
+
"Stop repeating the failing command. Summarize the root cause and switch to an alternative approach.";
|
|
883
|
+
}
|
|
884
|
+
}
|
|
794
885
|
const ladder = intervention.createInterventionLadder({
|
|
795
886
|
target: {
|
|
796
887
|
channel: payload.channel,
|
|
@@ -803,7 +894,7 @@ async function cmdInterveneRun(args) {
|
|
|
803
894
|
rolloutFile,
|
|
804
895
|
daemon: payload.daemon,
|
|
805
896
|
},
|
|
806
|
-
reinstructPrompt
|
|
897
|
+
reinstructPrompt,
|
|
807
898
|
readActivitySignature,
|
|
808
899
|
config: {
|
|
809
900
|
...(seconds(payload.reinstructWaitSec)
|
|
@@ -830,6 +921,307 @@ async function cmdInterveneRun(args) {
|
|
|
830
921
|
}
|
|
831
922
|
}
|
|
832
923
|
|
|
924
|
+
const PROGRESSING_GRACE_MEM = new Map();
|
|
925
|
+
|
|
926
|
+
function progressingGraceFilePath() {
|
|
927
|
+
return (
|
|
928
|
+
process.env.TFX_JEV_GRACE_FILE ||
|
|
929
|
+
join(tmpdir(), "tfx-jev-progressing-grace.json")
|
|
930
|
+
);
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
function loadProgressingGraceStore() {
|
|
934
|
+
try {
|
|
935
|
+
const file = progressingGraceFilePath();
|
|
936
|
+
if (!existsSync(file)) return {};
|
|
937
|
+
const parsed = JSON.parse(readFileSync(file, "utf8"));
|
|
938
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
939
|
+
} catch {
|
|
940
|
+
return {};
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
function hasGrantedProgressingGrace(targetKey, logSignature) {
|
|
945
|
+
if (!targetKey || !logSignature) return false;
|
|
946
|
+
if (PROGRESSING_GRACE_MEM.get(targetKey) === logSignature) return true;
|
|
947
|
+
const store = loadProgressingGraceStore();
|
|
948
|
+
return store[targetKey] === logSignature;
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
function recordProgressingGrace(targetKey, logSignature) {
|
|
952
|
+
if (!targetKey || !logSignature) return;
|
|
953
|
+
PROGRESSING_GRACE_MEM.set(targetKey, logSignature);
|
|
954
|
+
try {
|
|
955
|
+
const store = loadProgressingGraceStore();
|
|
956
|
+
store[targetKey] = logSignature;
|
|
957
|
+
const keys = Object.keys(store);
|
|
958
|
+
if (keys.length > 64) {
|
|
959
|
+
for (const oldKey of keys.slice(0, keys.length - 64)) {
|
|
960
|
+
delete store[oldKey];
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
writeFileSync(progressingGraceFilePath(), JSON.stringify(store), "utf8");
|
|
964
|
+
} catch {
|
|
965
|
+
// 상태 기록 실패는 무시
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
export function readTailSafe(filePath, maxBytes = 2000) {
|
|
970
|
+
if (!filePath) return "";
|
|
971
|
+
let fd;
|
|
972
|
+
try {
|
|
973
|
+
fd = openSync(String(filePath), "r");
|
|
974
|
+
const { size } = fstatSync(fd);
|
|
975
|
+
if (size <= 0) return "";
|
|
976
|
+
const readLen = Math.min(size, maxBytes);
|
|
977
|
+
const offset = Math.max(0, size - readLen);
|
|
978
|
+
const buf = Buffer.allocUnsafe(readLen);
|
|
979
|
+
const bytesRead = readSync(fd, buf, 0, readLen, offset);
|
|
980
|
+
return buf
|
|
981
|
+
.subarray(0, bytesRead)
|
|
982
|
+
.toString("utf8")
|
|
983
|
+
.replace(/^\uFFFD+/, "");
|
|
984
|
+
} catch {
|
|
985
|
+
return "";
|
|
986
|
+
} finally {
|
|
987
|
+
if (fd !== undefined) {
|
|
988
|
+
try {
|
|
989
|
+
closeSync(fd);
|
|
990
|
+
} catch {}
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
async function cmdJudgeStall(args) {
|
|
996
|
+
try {
|
|
997
|
+
const payload =
|
|
998
|
+
args["payload-file"] || args.payload ? readBridgePayload(args) : {};
|
|
999
|
+
const stdoutLog = args["stdout-log"] ?? payload.stdoutLog;
|
|
1000
|
+
const stderrLog = args["stderr-log"] ?? payload.stderrLog;
|
|
1001
|
+
const rolloutFile = args["rollout-file"] ?? payload.rolloutFile;
|
|
1002
|
+
const elapsedSec = Number(args["elapsed-sec"] ?? payload.elapsedSec) || 0;
|
|
1003
|
+
const { isJevEnabled, judgeWorkerHealth } = await import(
|
|
1004
|
+
"./lib/jev-addon.mjs"
|
|
1005
|
+
);
|
|
1006
|
+
if (!isJevEnabled()) {
|
|
1007
|
+
return emitJson({ ok: true, enabled: false, status: null });
|
|
1008
|
+
}
|
|
1009
|
+
const verdict = await judgeWorkerHealth({
|
|
1010
|
+
stdoutTail: readTailSafe(stdoutLog),
|
|
1011
|
+
stderrTail: readTailSafe(stderrLog),
|
|
1012
|
+
rolloutTail: readTailSafe(rolloutFile),
|
|
1013
|
+
elapsedSec,
|
|
1014
|
+
});
|
|
1015
|
+
return emitJson({
|
|
1016
|
+
ok: true,
|
|
1017
|
+
enabled: true,
|
|
1018
|
+
status: verdict?.status ?? null,
|
|
1019
|
+
confidence: verdict?.confidence ?? null,
|
|
1020
|
+
});
|
|
1021
|
+
} catch (error) {
|
|
1022
|
+
return emitJson({
|
|
1023
|
+
ok: false,
|
|
1024
|
+
enabled: false,
|
|
1025
|
+
status: null,
|
|
1026
|
+
error: error?.message || String(error),
|
|
1027
|
+
});
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
async function cmdJevBatch(args) {
|
|
1032
|
+
try {
|
|
1033
|
+
const payload = readBridgePayload(args);
|
|
1034
|
+
const state = String(payload.state ?? payload.context ?? "");
|
|
1035
|
+
const questions =
|
|
1036
|
+
payload.questions && typeof payload.questions === "object"
|
|
1037
|
+
? payload.questions
|
|
1038
|
+
: {};
|
|
1039
|
+
const { isJevEnabled, queryJevBatch } = await import("./lib/jev-addon.mjs");
|
|
1040
|
+
if (!isJevEnabled()) {
|
|
1041
|
+
return emitJson({
|
|
1042
|
+
ok: true,
|
|
1043
|
+
enabled: false,
|
|
1044
|
+
answers: null,
|
|
1045
|
+
});
|
|
1046
|
+
}
|
|
1047
|
+
const answers = await queryJevBatch({ state, questions });
|
|
1048
|
+
return emitJson({ ok: true, enabled: true, answers });
|
|
1049
|
+
} catch (error) {
|
|
1050
|
+
return emitJson({
|
|
1051
|
+
ok: false,
|
|
1052
|
+
enabled: false,
|
|
1053
|
+
answers: null,
|
|
1054
|
+
error: error?.message || String(error),
|
|
1055
|
+
});
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
async function cmdJevStats() {
|
|
1060
|
+
try {
|
|
1061
|
+
const { isJevEnabled, summarizeJevStats } = await import(
|
|
1062
|
+
"./lib/jev-addon.mjs"
|
|
1063
|
+
);
|
|
1064
|
+
const stats = summarizeJevStats();
|
|
1065
|
+
return emitJson({ ok: true, enabled: isJevEnabled(), stats });
|
|
1066
|
+
} catch (error) {
|
|
1067
|
+
return emitJson({
|
|
1068
|
+
ok: false,
|
|
1069
|
+
error: error?.message || String(error),
|
|
1070
|
+
});
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
async function cmdHandoffCheck(args) {
|
|
1075
|
+
try {
|
|
1076
|
+
const payload =
|
|
1077
|
+
args["payload-file"] || args.payload ? readBridgePayload(args) : {};
|
|
1078
|
+
const resultFile = args["result-file"] ?? payload.resultFile;
|
|
1079
|
+
const rawText =
|
|
1080
|
+
args.text ??
|
|
1081
|
+
payload.rawText ??
|
|
1082
|
+
(resultFile && existsSync(resultFile)
|
|
1083
|
+
? readFileSync(resultFile, "utf8")
|
|
1084
|
+
: "");
|
|
1085
|
+
const { isJevEnabled, judgeHandoffQuality } = await import(
|
|
1086
|
+
"./lib/jev-addon.mjs"
|
|
1087
|
+
);
|
|
1088
|
+
if (!isJevEnabled()) {
|
|
1089
|
+
return emitJson({ ok: true, enabled: false, verdict: null });
|
|
1090
|
+
}
|
|
1091
|
+
const verdict = await judgeHandoffQuality({
|
|
1092
|
+
rawText,
|
|
1093
|
+
handoff: payload.handoff ?? {
|
|
1094
|
+
status: payload.status ?? "ok",
|
|
1095
|
+
lead_action: payload.leadAction ?? "accept",
|
|
1096
|
+
files_changed: Array.isArray(payload.gitDiffFiles)
|
|
1097
|
+
? payload.gitDiffFiles
|
|
1098
|
+
: [],
|
|
1099
|
+
verdict: payload.verdict ?? "",
|
|
1100
|
+
},
|
|
1101
|
+
gitDiffFiles: Array.isArray(payload.gitDiffFiles)
|
|
1102
|
+
? payload.gitDiffFiles
|
|
1103
|
+
: [],
|
|
1104
|
+
});
|
|
1105
|
+
return emitJson({ ok: true, enabled: true, verdict });
|
|
1106
|
+
} catch (error) {
|
|
1107
|
+
return emitJson({
|
|
1108
|
+
ok: false,
|
|
1109
|
+
error: error?.message || String(error),
|
|
1110
|
+
});
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
async function cmdJudgeRoute(args) {
|
|
1115
|
+
try {
|
|
1116
|
+
const payload =
|
|
1117
|
+
args["payload-file"] || args.payload ? readBridgePayload(args) : {};
|
|
1118
|
+
const prompt = String(args.prompt ?? args.text ?? payload.prompt ?? "");
|
|
1119
|
+
const agentType = String(args.agent ?? payload.agentType ?? "executor");
|
|
1120
|
+
const cliType = String(args["cli-type"] ?? payload.cliType ?? "codex");
|
|
1121
|
+
const availableRaw =
|
|
1122
|
+
args["available-servers"] ?? payload.availableServers ?? "";
|
|
1123
|
+
const availableServers = Array.isArray(availableRaw)
|
|
1124
|
+
? availableRaw
|
|
1125
|
+
: String(availableRaw)
|
|
1126
|
+
.split(",")
|
|
1127
|
+
.map((s) => s.trim())
|
|
1128
|
+
.filter(Boolean);
|
|
1129
|
+
|
|
1130
|
+
const { isJevEnabled, judgeTaskRouting } = await import(
|
|
1131
|
+
"./lib/jev-addon.mjs"
|
|
1132
|
+
);
|
|
1133
|
+
if (!isJevEnabled()) {
|
|
1134
|
+
if (args.delimited) return true;
|
|
1135
|
+
return emitJson({ ok: true, enabled: false, routing: null });
|
|
1136
|
+
}
|
|
1137
|
+
const routing = await judgeTaskRouting({
|
|
1138
|
+
prompt,
|
|
1139
|
+
agentType,
|
|
1140
|
+
cliType,
|
|
1141
|
+
availableServers,
|
|
1142
|
+
});
|
|
1143
|
+
if (args.delimited) {
|
|
1144
|
+
if (!routing) return true;
|
|
1145
|
+
const RS = "\x1e";
|
|
1146
|
+
const fields = [
|
|
1147
|
+
routing.complexity || "",
|
|
1148
|
+
routing.codexProfile || "",
|
|
1149
|
+
routing.agyProfile || "",
|
|
1150
|
+
routing.claudeModel || "",
|
|
1151
|
+
routing.claudeEffort || "",
|
|
1152
|
+
String(routing.expectedDurationSec || ""),
|
|
1153
|
+
routing.executionMode || "",
|
|
1154
|
+
routing.mcpProfile || "",
|
|
1155
|
+
Array.isArray(routing.neededMcpServers)
|
|
1156
|
+
? routing.neededMcpServers.join(",")
|
|
1157
|
+
: "",
|
|
1158
|
+
String(routing.confidence ?? ""),
|
|
1159
|
+
];
|
|
1160
|
+
process.stdout.write(fields.join(RS));
|
|
1161
|
+
return true;
|
|
1162
|
+
}
|
|
1163
|
+
return emitJson({ ok: true, enabled: true, routing });
|
|
1164
|
+
} catch (error) {
|
|
1165
|
+
if (args.delimited) return false;
|
|
1166
|
+
return emitJson({
|
|
1167
|
+
ok: false,
|
|
1168
|
+
enabled: false,
|
|
1169
|
+
routing: null,
|
|
1170
|
+
error: error?.message || String(error),
|
|
1171
|
+
});
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
async function cmdJudgeAck(args) {
|
|
1176
|
+
try {
|
|
1177
|
+
const payload =
|
|
1178
|
+
args["payload-file"] || args.payload ? readBridgePayload(args) : {};
|
|
1179
|
+
const instruction = String(args.instruction ?? payload.instruction ?? "");
|
|
1180
|
+
const stdoutLog = args["stdout-log"] ?? payload.stdoutLog;
|
|
1181
|
+
const recentOutput = String(
|
|
1182
|
+
args.text ?? payload.recentOutput ?? readTailSafe(stdoutLog),
|
|
1183
|
+
);
|
|
1184
|
+
const { isJevEnabled, judgeInstructionAck } = await import(
|
|
1185
|
+
"./lib/jev-addon.mjs"
|
|
1186
|
+
);
|
|
1187
|
+
if (!isJevEnabled()) {
|
|
1188
|
+
return emitJson({ ok: true, enabled: false, verdict: null });
|
|
1189
|
+
}
|
|
1190
|
+
const verdict = await judgeInstructionAck({ instruction, recentOutput });
|
|
1191
|
+
return emitJson({ ok: true, enabled: true, verdict });
|
|
1192
|
+
} catch (error) {
|
|
1193
|
+
return emitJson({
|
|
1194
|
+
ok: false,
|
|
1195
|
+
error: error?.message || String(error),
|
|
1196
|
+
});
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
async function cmdJudgeReview(args) {
|
|
1201
|
+
try {
|
|
1202
|
+
const payload =
|
|
1203
|
+
args["payload-file"] || args.payload ? readBridgePayload(args) : {};
|
|
1204
|
+
const { isJevEnabled, judgeReviewGate } = await import(
|
|
1205
|
+
"./lib/jev-addon.mjs"
|
|
1206
|
+
);
|
|
1207
|
+
if (!isJevEnabled()) {
|
|
1208
|
+
return emitJson({ ok: true, enabled: false, verdict: null });
|
|
1209
|
+
}
|
|
1210
|
+
const verdict = await judgeReviewGate({
|
|
1211
|
+
diffStat: String(payload.diffStat ?? ""),
|
|
1212
|
+
handoffSummary: String(args.summary ?? payload.handoffSummary ?? ""),
|
|
1213
|
+
previousReviews: String(payload.previousReviews ?? ""),
|
|
1214
|
+
currentReview: String(args.text ?? payload.currentReview ?? ""),
|
|
1215
|
+
});
|
|
1216
|
+
return emitJson({ ok: true, enabled: true, verdict });
|
|
1217
|
+
} catch (error) {
|
|
1218
|
+
return emitJson({
|
|
1219
|
+
ok: false,
|
|
1220
|
+
error: error?.message || String(error),
|
|
1221
|
+
});
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
|
|
833
1225
|
export async function main(argv = process.argv.slice(2)) {
|
|
834
1226
|
const cmd = argv[0];
|
|
835
1227
|
const args = parseArgs(argv.slice(1));
|
|
@@ -857,9 +1249,23 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
857
1249
|
return await cmdRetryStatus(args);
|
|
858
1250
|
case "intervene-run":
|
|
859
1251
|
return await cmdInterveneRun(args);
|
|
1252
|
+
case "judge-stall":
|
|
1253
|
+
return await cmdJudgeStall(args);
|
|
1254
|
+
case "jev-batch":
|
|
1255
|
+
return await cmdJevBatch(args);
|
|
1256
|
+
case "jev-stats":
|
|
1257
|
+
return await cmdJevStats(args);
|
|
1258
|
+
case "handoff-check":
|
|
1259
|
+
return await cmdHandoffCheck(args);
|
|
1260
|
+
case "judge-route":
|
|
1261
|
+
return await cmdJudgeRoute(args);
|
|
1262
|
+
case "judge-ack":
|
|
1263
|
+
return await cmdJudgeAck(args);
|
|
1264
|
+
case "judge-review":
|
|
1265
|
+
return await cmdJudgeReview(args);
|
|
860
1266
|
default:
|
|
861
1267
|
console.error(
|
|
862
|
-
"사용법: bridge.mjs <team-info|team-task-list|team-task-update|team-send-message|daemon-probe|daemon-attach|daemon-wait|daemon-interrupt|retry-run|retry-status|intervene-run> [--옵션]",
|
|
1268
|
+
"사용법: bridge.mjs <team-info|team-task-list|team-task-update|team-send-message|daemon-probe|daemon-attach|daemon-wait|daemon-interrupt|retry-run|retry-status|intervene-run|judge-stall|jev-batch|jev-stats|handoff-check|judge-route|judge-ack|judge-review> [--옵션]",
|
|
863
1269
|
);
|
|
864
1270
|
process.exit(1);
|
|
865
1271
|
}
|