@triflux/remote 10.92.0 → 10.93.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/team/codex-queue.mjs +60 -0
- package/hub/team/native-peer.mjs +20 -2
- package/package.json +1 -1
package/hub/team/codex-queue.mjs
CHANGED
|
@@ -8,6 +8,8 @@ import { createInterface } from "node:readline";
|
|
|
8
8
|
import { StringDecoder } from "node:string_decoder";
|
|
9
9
|
import { promisify } from "node:util";
|
|
10
10
|
import { codexThreadNames } from "@triflux/core/hub/lib/codex-session-registry.mjs";
|
|
11
|
+
import { JsonRpcWsUdsClient } from "../workers/lib/jsonrpc-ws-uds.mjs";
|
|
12
|
+
import { resolveCodexSocket } from "./native-peer.mjs";
|
|
11
13
|
import { findCodexRollout } from "./session-context.mjs";
|
|
12
14
|
|
|
13
15
|
const execFileAsync = promisify(execFile);
|
|
@@ -188,7 +190,65 @@ export async function queueCodexMessage({
|
|
|
188
190
|
env = process.env,
|
|
189
191
|
execFn = execFileAsync,
|
|
190
192
|
spawnFn = spawn,
|
|
193
|
+
resolveSocket = resolveCodexSocket,
|
|
194
|
+
clientFactory = (options) => new JsonRpcWsUdsClient(options),
|
|
191
195
|
}) {
|
|
196
|
+
let socketPath;
|
|
197
|
+
try {
|
|
198
|
+
socketPath = resolveSocket(env.HOME || homedir(), env);
|
|
199
|
+
} catch (error) {
|
|
200
|
+
if (error.code !== "ENOENT") throw error;
|
|
201
|
+
}
|
|
202
|
+
if (socketPath) {
|
|
203
|
+
const client = clientFactory({ socketPath, connectTimeoutMs: 5000 });
|
|
204
|
+
let connected = false;
|
|
205
|
+
let addSent = false;
|
|
206
|
+
try {
|
|
207
|
+
await client.connect();
|
|
208
|
+
connected = true;
|
|
209
|
+
await client.request("initialize", {
|
|
210
|
+
clientInfo: { name: "triflux-tfx-live", version: "1.0.0" },
|
|
211
|
+
capabilities: { experimentalApi: true },
|
|
212
|
+
});
|
|
213
|
+
client.notify("initialized", {});
|
|
214
|
+
let cursor;
|
|
215
|
+
const seen = new Set();
|
|
216
|
+
do {
|
|
217
|
+
const page = await client.request(
|
|
218
|
+
"thread/loaded/list",
|
|
219
|
+
cursor ? { cursor } : {},
|
|
220
|
+
);
|
|
221
|
+
if (!Array.isArray(page?.data))
|
|
222
|
+
throw new Error("Cannot verify loaded Codex queue target");
|
|
223
|
+
if (page.data.some((item) => (item?.id ?? item) === threadId)) {
|
|
224
|
+
// TUI를 소유한 공유 daemon에 직접 큐를 추가한다.
|
|
225
|
+
addSent = true;
|
|
226
|
+
const result = await client.request("thread/queue/add", {
|
|
227
|
+
threadId,
|
|
228
|
+
input: [{ type: "text", text: message, text_elements: [] }],
|
|
229
|
+
clientUserMessageId: randomUUID(),
|
|
230
|
+
});
|
|
231
|
+
const id = result?.queuedSubmission?.id;
|
|
232
|
+
if (!id)
|
|
233
|
+
throw new Error("Missing queuedSubmission id after queue add");
|
|
234
|
+
return { queuedMessageId: id, via: "shared-daemon" };
|
|
235
|
+
}
|
|
236
|
+
cursor = page.nextCursor;
|
|
237
|
+
if (cursor && (typeof cursor !== "string" || seen.has(cursor)))
|
|
238
|
+
throw new Error("Cannot verify loaded Codex queue pagination");
|
|
239
|
+
seen.add(cursor);
|
|
240
|
+
} while (cursor);
|
|
241
|
+
// 별도 TUI는 공유 daemon에 없으므로 기존 디스크 큐 경로를 유지한다.
|
|
242
|
+
} catch (error) {
|
|
243
|
+
if (connected) {
|
|
244
|
+
if (addSent && typeof error.code !== "number") error.maybeQueued = true;
|
|
245
|
+
throw error;
|
|
246
|
+
}
|
|
247
|
+
// daemon 연결 실패 때만 기존 stdio 큐 경로로 넘긴다.
|
|
248
|
+
} finally {
|
|
249
|
+
client.close();
|
|
250
|
+
}
|
|
251
|
+
}
|
|
192
252
|
let addSent = false;
|
|
193
253
|
try {
|
|
194
254
|
const result = await withCodexAppServer(
|
package/hub/team/native-peer.mjs
CHANGED
|
@@ -150,12 +150,30 @@ export async function sendCodexPeer({
|
|
|
150
150
|
};
|
|
151
151
|
}
|
|
152
152
|
try {
|
|
153
|
-
await client.request("turn/start", {
|
|
153
|
+
const result = await client.request("turn/start", {
|
|
154
154
|
threadId,
|
|
155
155
|
input: [],
|
|
156
156
|
toolOutput: { name: "tfx_peer_wake", output: WAKE, retain: true },
|
|
157
157
|
});
|
|
158
|
-
|
|
158
|
+
const turn = result?.turn;
|
|
159
|
+
if (
|
|
160
|
+
typeof turn?.id !== "string" ||
|
|
161
|
+
!turn.id ||
|
|
162
|
+
!["inProgress", "completed"].includes(turn.status)
|
|
163
|
+
)
|
|
164
|
+
return {
|
|
165
|
+
status: "partial",
|
|
166
|
+
retrySafe: false,
|
|
167
|
+
modelReceipt: false,
|
|
168
|
+
error: `wake was not accepted after injection: ${turn?.error?.message || turn?.status || "missing turn"}. Do not resend automatically; inspect the target session`,
|
|
169
|
+
};
|
|
170
|
+
return {
|
|
171
|
+
status: "sent",
|
|
172
|
+
retrySafe: false,
|
|
173
|
+
modelReceipt: false,
|
|
174
|
+
turnId: turn.id,
|
|
175
|
+
turnStatus: turn.status,
|
|
176
|
+
};
|
|
159
177
|
} catch (error) {
|
|
160
178
|
return {
|
|
161
179
|
status: "partial",
|