@openai-lite/codex-feishu 0.1.6 → 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openai-lite/codex-feishu",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "Feishu bridge for Codex with dual-end synchronized conversations.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,16 +1,57 @@
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
 
5
- function getCodexSpawnOptions(base = {}) {
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();
6
32
  if (process.platform === "win32") {
7
- return {
8
- ...base,
9
- // Windows commonly resolves codex via codex.cmd; shell mode keeps it executable.
10
- shell: true,
11
- };
33
+ try {
34
+ if (!fs.existsSync(normalized)) {
35
+ return process.cwd();
36
+ }
37
+ } catch {
38
+ return process.cwd();
39
+ }
12
40
  }
13
- return base;
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);
14
55
  }
15
56
 
16
57
  function normalizeJsonRpcPayload(payload) {
@@ -88,14 +129,10 @@ async function probeSubcommand(codexBin, args, timeoutMs = 2_500) {
88
129
  let stdout = "";
89
130
  let stderr = "";
90
131
  let timer = null;
91
- const child = spawn(
92
- codexBin,
93
- args,
94
- getCodexSpawnOptions({
95
- stdio: ["ignore", "pipe", "pipe"],
96
- env: process.env,
97
- }),
98
- );
132
+ const child = spawnCodex(codexBin, args, {
133
+ stdio: ["ignore", "pipe", "pipe"],
134
+ env: process.env,
135
+ });
99
136
  child.stdout.on("data", (chunk) => {
100
137
  stdout += chunk.toString("utf8");
101
138
  });
@@ -150,10 +187,11 @@ async function probeSubcommand(codexBin, args, timeoutMs = 2_500) {
150
187
  export class AppServerClient extends EventEmitter {
151
188
  constructor(options = {}) {
152
189
  super();
153
- this.codexBin =
190
+ this.codexBin = normalizeExecutable(
154
191
  options.codexBin ||
155
192
  process.env.CODEX_BIN ||
156
- (process.platform === "win32" ? "codex.cmd" : "codex");
193
+ (process.platform === "win32" ? "codex.cmd" : "codex"),
194
+ );
157
195
  this.transport = options.transport || process.env.CODEX_FEISHU_TRANSPORT || "auto";
158
196
  this.protoCwd = options.protoCwd || process.env.CODEX_FEISHU_CWD || process.cwd();
159
197
  this.protoModel = options.protoModel || process.env.CODEX_FEISHU_MODEL || "gpt-5.3-codex";
@@ -254,15 +292,11 @@ export class AppServerClient extends EventEmitter {
254
292
  }
255
293
 
256
294
  async startLegacyAppServer() {
257
- const child = spawn(
258
- this.codexBin,
259
- ["app-server", "--listen", "stdio://"],
260
- getCodexSpawnOptions({
261
- stdio: ["pipe", "pipe", "pipe"],
262
- env: process.env,
263
- cwd: this.protoCwd,
264
- }),
265
- );
295
+ const child = spawnCodex(this.codexBin, ["app-server", "--listen", "stdio://"], {
296
+ stdio: ["pipe", "pipe", "pipe"],
297
+ env: process.env,
298
+ cwd: this.protoCwd,
299
+ });
266
300
  this.process = child;
267
301
 
268
302
  child.on("error", (err) => {
@@ -331,15 +365,11 @@ export class AppServerClient extends EventEmitter {
331
365
  }
332
366
 
333
367
  async startProto() {
334
- const child = spawn(
335
- this.codexBin,
336
- ["proto"],
337
- getCodexSpawnOptions({
338
- stdio: ["pipe", "pipe", "pipe"],
339
- env: process.env,
340
- cwd: this.protoCwd,
341
- }),
342
- );
368
+ const child = spawnCodex(this.codexBin, ["proto"], {
369
+ stdio: ["pipe", "pipe", "pipe"],
370
+ env: process.env,
371
+ cwd: this.protoCwd,
372
+ });
343
373
  this.process = child;
344
374
  this.protoReady = {};
345
375