@openai-lite/codex-feishu 0.1.5 → 0.1.7
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/package.json
CHANGED
package/src/commands/daemon.js
CHANGED
|
@@ -5944,6 +5944,13 @@ export async function runDaemon() {
|
|
|
5944
5944
|
signal: info.signal ?? null,
|
|
5945
5945
|
});
|
|
5946
5946
|
});
|
|
5947
|
+
app.on("error", async (err) => {
|
|
5948
|
+
await appendEvent(store, {
|
|
5949
|
+
source: "app_server",
|
|
5950
|
+
type: "error",
|
|
5951
|
+
error: err?.message ?? String(err),
|
|
5952
|
+
});
|
|
5953
|
+
});
|
|
5947
5954
|
|
|
5948
5955
|
try {
|
|
5949
5956
|
await app.ensureStarted();
|
|
@@ -1,7 +1,59 @@
|
|
|
1
1
|
import { EventEmitter, once } from "node:events";
|
|
2
|
+
import fs from "node:fs";
|
|
2
3
|
import { spawn } from "node:child_process";
|
|
3
4
|
import readline from "node:readline";
|
|
4
5
|
|
|
6
|
+
function normalizeExecutable(raw) {
|
|
7
|
+
const text = String(raw ?? "").trim();
|
|
8
|
+
if (!text) {
|
|
9
|
+
return text;
|
|
10
|
+
}
|
|
11
|
+
const quoted =
|
|
12
|
+
(text.startsWith('"') && text.endsWith('"')) || (text.startsWith("'") && text.endsWith("'"));
|
|
13
|
+
return quoted ? text.slice(1, -1).trim() : text;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function quoteForCmd(arg) {
|
|
17
|
+
const text = String(arg ?? "");
|
|
18
|
+
if (text.length === 0) {
|
|
19
|
+
return '""';
|
|
20
|
+
}
|
|
21
|
+
if (!/[\s"&|<>^()]/.test(text)) {
|
|
22
|
+
return text;
|
|
23
|
+
}
|
|
24
|
+
return `"${text.replace(/"/g, '""')}"`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function sanitizeSpawnCwd(cwd) {
|
|
28
|
+
if (typeof cwd !== "string" || !cwd.trim()) {
|
|
29
|
+
return process.cwd();
|
|
30
|
+
}
|
|
31
|
+
const normalized = cwd.trim();
|
|
32
|
+
if (process.platform === "win32") {
|
|
33
|
+
try {
|
|
34
|
+
if (!fs.existsSync(normalized)) {
|
|
35
|
+
return process.cwd();
|
|
36
|
+
}
|
|
37
|
+
} catch {
|
|
38
|
+
return process.cwd();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return normalized;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function spawnCodex(codexBin, args, options = {}) {
|
|
45
|
+
const bin = normalizeExecutable(codexBin);
|
|
46
|
+
const spawnOptions = {
|
|
47
|
+
...options,
|
|
48
|
+
cwd: sanitizeSpawnCwd(options.cwd),
|
|
49
|
+
};
|
|
50
|
+
if (process.platform !== "win32") {
|
|
51
|
+
return spawn(bin, args, spawnOptions);
|
|
52
|
+
}
|
|
53
|
+
const command = [bin, ...args].map(quoteForCmd).join(" ");
|
|
54
|
+
return spawn("cmd.exe", ["/d", "/s", "/c", command], spawnOptions);
|
|
55
|
+
}
|
|
56
|
+
|
|
5
57
|
function normalizeJsonRpcPayload(payload) {
|
|
6
58
|
if (!payload || typeof payload !== "object") {
|
|
7
59
|
return null;
|
|
@@ -77,7 +129,7 @@ async function probeSubcommand(codexBin, args, timeoutMs = 2_500) {
|
|
|
77
129
|
let stdout = "";
|
|
78
130
|
let stderr = "";
|
|
79
131
|
let timer = null;
|
|
80
|
-
const child =
|
|
132
|
+
const child = spawnCodex(codexBin, args, {
|
|
81
133
|
stdio: ["ignore", "pipe", "pipe"],
|
|
82
134
|
env: process.env,
|
|
83
135
|
});
|
|
@@ -135,7 +187,11 @@ async function probeSubcommand(codexBin, args, timeoutMs = 2_500) {
|
|
|
135
187
|
export class AppServerClient extends EventEmitter {
|
|
136
188
|
constructor(options = {}) {
|
|
137
189
|
super();
|
|
138
|
-
this.codexBin =
|
|
190
|
+
this.codexBin = normalizeExecutable(
|
|
191
|
+
options.codexBin ||
|
|
192
|
+
process.env.CODEX_BIN ||
|
|
193
|
+
(process.platform === "win32" ? "codex.cmd" : "codex"),
|
|
194
|
+
);
|
|
139
195
|
this.transport = options.transport || process.env.CODEX_FEISHU_TRANSPORT || "auto";
|
|
140
196
|
this.protoCwd = options.protoCwd || process.env.CODEX_FEISHU_CWD || process.cwd();
|
|
141
197
|
this.protoModel = options.protoModel || process.env.CODEX_FEISHU_MODEL || "gpt-5.3-codex";
|
|
@@ -236,7 +292,7 @@ export class AppServerClient extends EventEmitter {
|
|
|
236
292
|
}
|
|
237
293
|
|
|
238
294
|
async startLegacyAppServer() {
|
|
239
|
-
const child =
|
|
295
|
+
const child = spawnCodex(this.codexBin, ["app-server", "--listen", "stdio://"], {
|
|
240
296
|
stdio: ["pipe", "pipe", "pipe"],
|
|
241
297
|
env: process.env,
|
|
242
298
|
cwd: this.protoCwd,
|
|
@@ -309,7 +365,7 @@ export class AppServerClient extends EventEmitter {
|
|
|
309
365
|
}
|
|
310
366
|
|
|
311
367
|
async startProto() {
|
|
312
|
-
const child =
|
|
368
|
+
const child = spawnCodex(this.codexBin, ["proto"], {
|
|
313
369
|
stdio: ["pipe", "pipe", "pipe"],
|
|
314
370
|
env: process.env,
|
|
315
371
|
cwd: this.protoCwd,
|
|
@@ -56,6 +56,22 @@ async function isDaemonRpcResponsive(timeoutMs = 1000) {
|
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
async function readLogTail(logPath, maxLines = 60) {
|
|
60
|
+
try {
|
|
61
|
+
const text = await readTextIfExists(logPath);
|
|
62
|
+
if (!text) {
|
|
63
|
+
return "";
|
|
64
|
+
}
|
|
65
|
+
const lines = text
|
|
66
|
+
.split(/\r?\n/)
|
|
67
|
+
.filter((line) => line.trim().length > 0)
|
|
68
|
+
.slice(-maxLines);
|
|
69
|
+
return lines.join("\n");
|
|
70
|
+
} catch {
|
|
71
|
+
return "";
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
59
75
|
async function stopByPid(pid, timeoutMs = 3000) {
|
|
60
76
|
if (!isPidAlive(pid)) {
|
|
61
77
|
return { action: "already_stopped", pid };
|
|
@@ -201,7 +217,7 @@ export async function restartDaemonDetached() {
|
|
|
201
217
|
for (const cliEntry of candidateEntries) {
|
|
202
218
|
attempts.push([process.execPath, [cliEntry, "daemon"]]);
|
|
203
219
|
}
|
|
204
|
-
attempts.push(["
|
|
220
|
+
attempts.push(["cmd.exe", ["/d", "/s", "/c", "codex-feishu daemon"]]);
|
|
205
221
|
} else {
|
|
206
222
|
attempts.push(["codex-feishu", ["daemon"]]);
|
|
207
223
|
for (const cliEntry of candidateEntries) {
|
|
@@ -234,8 +250,10 @@ export async function restartDaemonDetached() {
|
|
|
234
250
|
failedAttempts.push(`${cmd} ${args.join(" ")} => ${startResult.error}`);
|
|
235
251
|
}
|
|
236
252
|
if (!startResult.ok) {
|
|
253
|
+
const logTail = await readLogTail(logPath, 80);
|
|
237
254
|
const details = failedAttempts.length > 0 ? `; attempts: ${failedAttempts.join(" | ")}` : "";
|
|
238
|
-
|
|
255
|
+
const logHint = logTail ? `; daemon.log tail:\n${logTail}` : "";
|
|
256
|
+
throw new Error(`failed to start daemon in background: ${startResult.error}${details}${logHint}`);
|
|
239
257
|
}
|
|
240
258
|
|
|
241
259
|
if (startResult.pid) {
|