@modelzen/feishu-codex-bridge 0.2.0 → 0.2.1-win
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/cli.js +342 -95
- package/package.json +3 -1
package/dist/cli.js
CHANGED
|
@@ -15,7 +15,6 @@ function bridgeVersion() {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
// src/cli/commands/doctor.ts
|
|
18
|
-
import { execFileSync as execFileSync2 } from "child_process";
|
|
19
18
|
import { existsSync as existsSync3 } from "fs";
|
|
20
19
|
import { homedir as homedir2 } from "os";
|
|
21
20
|
import { join as join4 } from "path";
|
|
@@ -269,27 +268,56 @@ async function moveIfExists(src, dest) {
|
|
|
269
268
|
}
|
|
270
269
|
|
|
271
270
|
// src/agent/codex-appserver/locate.ts
|
|
272
|
-
import { execFileSync } from "child_process";
|
|
273
271
|
import { existsSync as existsSync2 } from "fs";
|
|
274
|
-
import { join as join3 } from "path";
|
|
272
|
+
import { extname, join as join3 } from "path";
|
|
273
|
+
|
|
274
|
+
// src/platform/spawn.ts
|
|
275
|
+
import crossSpawn from "cross-spawn";
|
|
276
|
+
function spawnProcess(command, args = [], options = {}) {
|
|
277
|
+
return crossSpawn(command, [...args], options);
|
|
278
|
+
}
|
|
279
|
+
function spawnProcessSync(command, args = [], options = {}) {
|
|
280
|
+
return crossSpawn.sync(command, [...args], options);
|
|
281
|
+
}
|
|
282
|
+
function mergeProcessEnv(base = process.env, overrides = {}) {
|
|
283
|
+
const out = { ...base };
|
|
284
|
+
for (const [key, value] of Object.entries(overrides)) {
|
|
285
|
+
for (const existing of Object.keys(out)) {
|
|
286
|
+
if (existing.toLowerCase() === key.toLowerCase()) delete out[existing];
|
|
287
|
+
}
|
|
288
|
+
if (value !== void 0) out[key] = value;
|
|
289
|
+
}
|
|
290
|
+
return out;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// src/agent/codex-appserver/locate.ts
|
|
294
|
+
var IS_WIN = process.platform === "win32";
|
|
275
295
|
function resolveCodexBin() {
|
|
276
296
|
const env = process.env.CODEX_BIN;
|
|
277
297
|
if (env && existsSync2(env)) return env;
|
|
278
298
|
const onPath = which("codex");
|
|
279
299
|
if (onPath) return onPath;
|
|
280
|
-
const
|
|
281
|
-
|
|
300
|
+
for (const cand of execCandidates(paths.codexCliBinDir, "codex")) {
|
|
301
|
+
if (existsSync2(cand)) return cand;
|
|
302
|
+
}
|
|
282
303
|
const appBundle = "/Applications/Codex.app/Contents/Resources/codex";
|
|
283
304
|
if (process.platform === "darwin" && existsSync2(appBundle)) return appBundle;
|
|
284
305
|
return null;
|
|
285
306
|
}
|
|
307
|
+
function execCandidates(dir, base) {
|
|
308
|
+
const exact = join3(dir, base);
|
|
309
|
+
if (!IS_WIN || extname(base)) return [exact];
|
|
310
|
+
const exts = (process.env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").map((e) => e.trim()).filter(Boolean);
|
|
311
|
+
return [exact, ...exts.map((e) => join3(dir, base + e.toLowerCase()))];
|
|
312
|
+
}
|
|
286
313
|
function which(cmd) {
|
|
287
314
|
try {
|
|
288
|
-
const
|
|
315
|
+
const res = spawnProcessSync(IS_WIN ? "where" : "which", [cmd], {
|
|
289
316
|
encoding: "utf8",
|
|
290
317
|
stdio: ["ignore", "pipe", "ignore"]
|
|
291
318
|
});
|
|
292
|
-
|
|
319
|
+
if (res.status !== 0 || typeof res.stdout !== "string") return null;
|
|
320
|
+
const first = res.stdout.split("\n").map((l) => l.trim()).find(Boolean);
|
|
293
321
|
return first && existsSync2(first) ? first : null;
|
|
294
322
|
} catch {
|
|
295
323
|
return null;
|
|
@@ -297,7 +325,9 @@ function which(cmd) {
|
|
|
297
325
|
}
|
|
298
326
|
function codexVersion(bin) {
|
|
299
327
|
try {
|
|
300
|
-
|
|
328
|
+
const res = spawnProcessSync(bin, ["--version"], { encoding: "utf8" });
|
|
329
|
+
if (res.status !== 0 || typeof res.stdout !== "string") return null;
|
|
330
|
+
return res.stdout.trim();
|
|
301
331
|
} catch {
|
|
302
332
|
return null;
|
|
303
333
|
}
|
|
@@ -355,7 +385,9 @@ ${failed === 0 ? "\u5168\u90E8\u901A\u8FC7 \u2713" : `${failed} \u9879\u9700\u59
|
|
|
355
385
|
}
|
|
356
386
|
function tryExec(cmd, args) {
|
|
357
387
|
try {
|
|
358
|
-
|
|
388
|
+
const res = spawnProcessSync(cmd, args, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
|
|
389
|
+
if (res.status !== 0 || typeof res.stdout !== "string") return null;
|
|
390
|
+
return res.stdout.trim();
|
|
359
391
|
} catch {
|
|
360
392
|
return null;
|
|
361
393
|
}
|
|
@@ -538,7 +570,7 @@ async function spawnExecProvider(pc, ref) {
|
|
|
538
570
|
const timeoutMs = pc.noOutputTimeoutMs ?? DEFAULT_EXEC_TIMEOUT_MS;
|
|
539
571
|
const maxOutput = pc.maxOutputBytes ?? DEFAULT_EXEC_MAX_OUTPUT;
|
|
540
572
|
const providerName = ref.provider ?? DEFAULT_PROVIDER;
|
|
541
|
-
return new Promise((
|
|
573
|
+
return new Promise((resolve7, reject) => {
|
|
542
574
|
const env = {};
|
|
543
575
|
if (pc.passEnv) for (const k of pc.passEnv) {
|
|
544
576
|
const v = process.env[k];
|
|
@@ -583,7 +615,7 @@ async function spawnExecProvider(pc, ref) {
|
|
|
583
615
|
try {
|
|
584
616
|
const parsed = JSON.parse(stdout);
|
|
585
617
|
const value = parsed.values?.[ref.id];
|
|
586
|
-
if (typeof value === "string") return
|
|
618
|
+
if (typeof value === "string") return resolve7(value);
|
|
587
619
|
const err = parsed.errors?.[ref.id]?.message;
|
|
588
620
|
reject(new Error(`exec provider did not return secret for ${ref.id}${err ? `: ${err}` : ""}`));
|
|
589
621
|
} catch (err) {
|
|
@@ -1131,7 +1163,6 @@ ${rule}`);
|
|
|
1131
1163
|
import { createLarkChannel, Domain } from "@larksuiteoapi/node-sdk";
|
|
1132
1164
|
|
|
1133
1165
|
// src/agent/codex-appserver/app-server-client.ts
|
|
1134
|
-
import { spawn as spawn3 } from "child_process";
|
|
1135
1166
|
var AsyncQueue = class {
|
|
1136
1167
|
items = [];
|
|
1137
1168
|
waiters = [];
|
|
@@ -1152,7 +1183,7 @@ var AsyncQueue = class {
|
|
|
1152
1183
|
continue;
|
|
1153
1184
|
}
|
|
1154
1185
|
if (this.closed) return;
|
|
1155
|
-
const next = await new Promise((
|
|
1186
|
+
const next = await new Promise((resolve7) => this.waiters.push(resolve7));
|
|
1156
1187
|
if (next.done) return;
|
|
1157
1188
|
yield next.value;
|
|
1158
1189
|
}
|
|
@@ -1174,9 +1205,9 @@ var AppServerClient = class {
|
|
|
1174
1205
|
}
|
|
1175
1206
|
/** spawn + initialize handshake. Throws if spawn/handshake fails. */
|
|
1176
1207
|
async connect() {
|
|
1177
|
-
const child =
|
|
1208
|
+
const child = spawnProcess(this.opts.bin, ["app-server", "--listen", "stdio://"], {
|
|
1178
1209
|
cwd: this.opts.cwd,
|
|
1179
|
-
env:
|
|
1210
|
+
env: mergeProcessEnv(process.env, { ...this.opts.env, FEISHU_CODEX_BRIDGE: "1" }),
|
|
1180
1211
|
stdio: ["pipe", "pipe", "pipe"]
|
|
1181
1212
|
});
|
|
1182
1213
|
this.child = child;
|
|
@@ -1203,8 +1234,8 @@ var AppServerClient = class {
|
|
|
1203
1234
|
const id = ++this.nextId;
|
|
1204
1235
|
const payload = `${JSON.stringify({ jsonrpc: "2.0", id, method, params: params ?? {} })}
|
|
1205
1236
|
`;
|
|
1206
|
-
return new Promise((
|
|
1207
|
-
this.pending.set(id, { resolve:
|
|
1237
|
+
return new Promise((resolve7, reject) => {
|
|
1238
|
+
this.pending.set(id, { resolve: resolve7, reject });
|
|
1208
1239
|
this.child.stdin.write(payload, (err) => {
|
|
1209
1240
|
if (err) {
|
|
1210
1241
|
this.pending.delete(id);
|
|
@@ -1227,15 +1258,36 @@ var AppServerClient = class {
|
|
|
1227
1258
|
this.closed = true;
|
|
1228
1259
|
const child = this.child;
|
|
1229
1260
|
if (!child || child.exitCode !== null) return;
|
|
1261
|
+
if (process.platform === "win32" && child.pid) {
|
|
1262
|
+
await new Promise((resolve7) => {
|
|
1263
|
+
let settled = false;
|
|
1264
|
+
const done = () => {
|
|
1265
|
+
if (settled) return;
|
|
1266
|
+
settled = true;
|
|
1267
|
+
clearTimeout(t);
|
|
1268
|
+
resolve7();
|
|
1269
|
+
};
|
|
1270
|
+
const t = setTimeout(done, graceMs);
|
|
1271
|
+
child.once("exit", done);
|
|
1272
|
+
spawnProcess("taskkill", ["/pid", String(child.pid), "/T", "/F"], { stdio: "ignore" }).on(
|
|
1273
|
+
"error",
|
|
1274
|
+
() => {
|
|
1275
|
+
child.kill();
|
|
1276
|
+
done();
|
|
1277
|
+
}
|
|
1278
|
+
);
|
|
1279
|
+
});
|
|
1280
|
+
return;
|
|
1281
|
+
}
|
|
1230
1282
|
child.kill("SIGTERM");
|
|
1231
|
-
await new Promise((
|
|
1283
|
+
await new Promise((resolve7) => {
|
|
1232
1284
|
const t = setTimeout(() => {
|
|
1233
1285
|
if (child.exitCode === null) child.kill("SIGKILL");
|
|
1234
|
-
|
|
1286
|
+
resolve7();
|
|
1235
1287
|
}, graceMs);
|
|
1236
1288
|
child.once("exit", () => {
|
|
1237
1289
|
clearTimeout(t);
|
|
1238
|
-
|
|
1290
|
+
resolve7();
|
|
1239
1291
|
});
|
|
1240
1292
|
});
|
|
1241
1293
|
}
|
|
@@ -1368,12 +1420,12 @@ var BRIDGE_DEVELOPER_INSTRUCTIONS = [
|
|
|
1368
1420
|
].join("\n");
|
|
1369
1421
|
var READ_HISTORY_TIMEOUT_MS = 2e4;
|
|
1370
1422
|
function withDeadline(p, ms, label) {
|
|
1371
|
-
return new Promise((
|
|
1423
|
+
return new Promise((resolve7, reject) => {
|
|
1372
1424
|
const t = setTimeout(() => reject(new Error(`${label} timed out after ${ms}ms`)), ms);
|
|
1373
1425
|
p.then(
|
|
1374
1426
|
(v) => {
|
|
1375
1427
|
clearTimeout(t);
|
|
1376
|
-
|
|
1428
|
+
resolve7(v);
|
|
1377
1429
|
},
|
|
1378
1430
|
(e) => {
|
|
1379
1431
|
clearTimeout(t);
|
|
@@ -1413,11 +1465,11 @@ var CodexThread = class {
|
|
|
1413
1465
|
if (self.model) params.model = self.model;
|
|
1414
1466
|
if (self.effort) params.effort = self.effort;
|
|
1415
1467
|
let startError;
|
|
1416
|
-
const startFailed = new Promise((
|
|
1468
|
+
const startFailed = new Promise((resolve7) => {
|
|
1417
1469
|
self.client.request("turn/start", params).then(void 0, (err) => {
|
|
1418
1470
|
startError = err instanceof Error ? err : new Error(String(err));
|
|
1419
1471
|
log.fail("agent", startError, { phase: "turn/start" });
|
|
1420
|
-
|
|
1472
|
+
resolve7("start-failed");
|
|
1421
1473
|
});
|
|
1422
1474
|
});
|
|
1423
1475
|
const stream2 = self.client.stream()[Symbol.asyncIterator]();
|
|
@@ -2788,7 +2840,7 @@ var RunCardStream = class {
|
|
|
2788
2840
|
|
|
2789
2841
|
// src/card/outbound-images.ts
|
|
2790
2842
|
import { readFile as readFile5, stat as stat2 } from "fs/promises";
|
|
2791
|
-
import { extname, isAbsolute, resolve as resolve2, sep } from "path";
|
|
2843
|
+
import { extname as extname2, isAbsolute, resolve as resolve2, sep } from "path";
|
|
2792
2844
|
var MAX_IMAGES = 9;
|
|
2793
2845
|
var MAX_BYTES = 10 * 1024 * 1024;
|
|
2794
2846
|
var DOWNLOAD_TIMEOUT_MS = 1e4;
|
|
@@ -2854,7 +2906,7 @@ async function loadLocal(src, cwd) {
|
|
|
2854
2906
|
log.warn("outbound", "image-outside-cwd", { src: src.slice(0, 80) });
|
|
2855
2907
|
return { cacheKey: `local:${abs}` };
|
|
2856
2908
|
}
|
|
2857
|
-
const ext =
|
|
2909
|
+
const ext = extname2(abs).slice(1).toLowerCase();
|
|
2858
2910
|
if (!ALLOWED_EXT.has(ext)) {
|
|
2859
2911
|
log.warn("outbound", "image-ext", { ext, src: src.slice(0, 80) });
|
|
2860
2912
|
return { cacheKey: `local:${abs}` };
|
|
@@ -3385,29 +3437,40 @@ function buildGroupSettingsCard(project) {
|
|
|
3385
3437
|
}
|
|
3386
3438
|
|
|
3387
3439
|
// src/service/update.ts
|
|
3388
|
-
import { execFile, spawn as
|
|
3389
|
-
import { existsSync as
|
|
3390
|
-
import { dirname as
|
|
3391
|
-
import { fileURLToPath as
|
|
3440
|
+
import { execFile, spawn as spawn4 } from "child_process";
|
|
3441
|
+
import { existsSync as existsSync6, readFileSync as readFileSync2 } from "fs";
|
|
3442
|
+
import { dirname as dirname8, join as join10, resolve as resolve5 } from "path";
|
|
3443
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
3392
3444
|
import { promisify } from "util";
|
|
3393
3445
|
|
|
3394
3446
|
// src/service/launchd.ts
|
|
3395
|
-
import { spawn as
|
|
3447
|
+
import { spawn as spawn3, spawnSync } from "child_process";
|
|
3396
3448
|
import { existsSync as existsSync4 } from "fs";
|
|
3397
|
-
import {
|
|
3449
|
+
import { mkdir as mkdir6, rm as rm2, writeFile as writeFile5 } from "fs/promises";
|
|
3398
3450
|
import { homedir as homedir3, userInfo as userInfo2 } from "os";
|
|
3399
|
-
import { dirname as dirname6, join as
|
|
3451
|
+
import { dirname as dirname6, join as join8, resolve as resolve3 } from "path";
|
|
3400
3452
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
}
|
|
3453
|
+
|
|
3454
|
+
// src/service/common.ts
|
|
3455
|
+
import { appendFile, mkdir as mkdir5 } from "fs/promises";
|
|
3456
|
+
import { join as join7 } from "path";
|
|
3405
3457
|
function serviceStdoutPath() {
|
|
3406
3458
|
return join7(paths.appDir, "service.log");
|
|
3407
3459
|
}
|
|
3408
3460
|
function serviceStderrPath() {
|
|
3409
3461
|
return join7(paths.appDir, "service.err.log");
|
|
3410
3462
|
}
|
|
3463
|
+
async function ensureLogFiles() {
|
|
3464
|
+
await mkdir5(paths.appDir, { recursive: true });
|
|
3465
|
+
await appendFile(serviceStdoutPath(), "");
|
|
3466
|
+
await appendFile(serviceStderrPath(), "");
|
|
3467
|
+
}
|
|
3468
|
+
|
|
3469
|
+
// src/service/launchd.ts
|
|
3470
|
+
var LAUNCHD_LABEL = "ai.feishu-codex-bridge.bot";
|
|
3471
|
+
function launchAgentPlistPath() {
|
|
3472
|
+
return join8(homedir3(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
|
|
3473
|
+
}
|
|
3411
3474
|
function resolveCliBinPath() {
|
|
3412
3475
|
const distDir = dirname6(fileURLToPath2(import.meta.url));
|
|
3413
3476
|
return resolve3(distDir, "..", "bin", "feishu-codex-bridge.mjs");
|
|
@@ -3450,7 +3513,7 @@ function buildPlist() {
|
|
|
3450
3513
|
}
|
|
3451
3514
|
async function installLaunchd() {
|
|
3452
3515
|
const plistPath = launchAgentPlistPath();
|
|
3453
|
-
await
|
|
3516
|
+
await mkdir6(dirname6(plistPath), { recursive: true });
|
|
3454
3517
|
await ensureLogFiles();
|
|
3455
3518
|
await writeFile5(plistPath, buildPlist(), "utf8");
|
|
3456
3519
|
if (isLoaded()) {
|
|
@@ -3488,9 +3551,10 @@ function statusLaunchd() {
|
|
|
3488
3551
|
const raw = result.stdout || result.stderr;
|
|
3489
3552
|
const parsed = parseLaunchdStatus(raw);
|
|
3490
3553
|
return {
|
|
3554
|
+
platformName: "launchd (macOS)",
|
|
3491
3555
|
installed: existsSync4(launchAgentPlistPath()),
|
|
3492
|
-
|
|
3493
|
-
|
|
3556
|
+
running: result.ok,
|
|
3557
|
+
servicePath: launchAgentPlistPath(),
|
|
3494
3558
|
stdoutPath: serviceStdoutPath(),
|
|
3495
3559
|
stderrPath: serviceStderrPath(),
|
|
3496
3560
|
pid: parsed.pid,
|
|
@@ -3502,7 +3566,7 @@ async function tailLaunchdLogs(follow) {
|
|
|
3502
3566
|
await ensureLogFiles();
|
|
3503
3567
|
const args = follow ? ["-f", serviceStdoutPath(), serviceStderrPath()] : ["-n", "100", serviceStdoutPath(), serviceStderrPath()];
|
|
3504
3568
|
await new Promise((resolvePromise, reject) => {
|
|
3505
|
-
const child =
|
|
3569
|
+
const child = spawn3("tail", args, { stdio: "inherit" });
|
|
3506
3570
|
child.on("error", reject);
|
|
3507
3571
|
child.on("close", (code) => {
|
|
3508
3572
|
if (code === 0 || follow && code === null) {
|
|
@@ -3533,11 +3597,6 @@ async function waitUntilUnloaded(timeoutMs = 5e3) {
|
|
|
3533
3597
|
}
|
|
3534
3598
|
throw new Error(`launchd service \u672A\u5728 ${timeoutMs}ms \u5185\u5378\u8F7D\u5B8C\u6210`);
|
|
3535
3599
|
}
|
|
3536
|
-
async function ensureLogFiles() {
|
|
3537
|
-
await mkdir5(paths.appDir, { recursive: true });
|
|
3538
|
-
await appendFile(serviceStdoutPath(), "");
|
|
3539
|
-
await appendFile(serviceStderrPath(), "");
|
|
3540
|
-
}
|
|
3541
3600
|
function userTarget() {
|
|
3542
3601
|
return `gui/${userInfo2().uid}`;
|
|
3543
3602
|
}
|
|
@@ -3558,29 +3617,218 @@ function launchctlError(command, result) {
|
|
|
3558
3617
|
return new Error(`${command} \u5931\u8D25\uFF08exit ${result.status ?? "unknown"}\uFF09${output ? `\uFF1A${output}` : ""}`);
|
|
3559
3618
|
}
|
|
3560
3619
|
|
|
3620
|
+
// src/service/schtasks.ts
|
|
3621
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
3622
|
+
import { createReadStream, existsSync as existsSync5, statSync } from "fs";
|
|
3623
|
+
import { mkdir as mkdir7, readFile as readFile7, rm as rm3, writeFile as writeFile6 } from "fs/promises";
|
|
3624
|
+
import { dirname as dirname7, join as join9, resolve as resolve4 } from "path";
|
|
3625
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
3626
|
+
var WINDOWS_TASK_NAME = "feishu-codex-bridge";
|
|
3627
|
+
function launcherCmdPath() {
|
|
3628
|
+
return join9(paths.appDir, "service-launcher.cmd");
|
|
3629
|
+
}
|
|
3630
|
+
function resolveCliBinPath2() {
|
|
3631
|
+
const distDir = dirname7(fileURLToPath3(import.meta.url));
|
|
3632
|
+
return resolve4(distDir, "..", "bin", "feishu-codex-bridge.mjs");
|
|
3633
|
+
}
|
|
3634
|
+
function buildLauncherCmd() {
|
|
3635
|
+
const nodePath = process.execPath;
|
|
3636
|
+
const cliBinPath = resolveCliBinPath2();
|
|
3637
|
+
const pathEnv = process.env.PATH ?? "";
|
|
3638
|
+
return [
|
|
3639
|
+
"@echo off",
|
|
3640
|
+
`set "PATH=${pathEnv}"`,
|
|
3641
|
+
`"${nodePath}" "${cliBinPath}" run >> "${serviceStdoutPath()}" 2>> "${serviceStderrPath()}"`,
|
|
3642
|
+
""
|
|
3643
|
+
].join("\r\n");
|
|
3644
|
+
}
|
|
3645
|
+
function runSchtasks(args) {
|
|
3646
|
+
const r = spawnSync2("schtasks", args, { encoding: "utf8" });
|
|
3647
|
+
return {
|
|
3648
|
+
ok: r.status === 0,
|
|
3649
|
+
status: r.status,
|
|
3650
|
+
stdout: r.stdout ?? "",
|
|
3651
|
+
stderr: r.stderr ?? ""
|
|
3652
|
+
};
|
|
3653
|
+
}
|
|
3654
|
+
function schtasksError(command, r) {
|
|
3655
|
+
const out = [r.stderr.trim(), r.stdout.trim()].filter(Boolean).join("\n");
|
|
3656
|
+
return new Error(`${command} \u5931\u8D25\uFF08exit ${r.status ?? "unknown"}\uFF09${out ? `\uFF1A${out}` : ""}`);
|
|
3657
|
+
}
|
|
3658
|
+
async function writeLauncherCmd() {
|
|
3659
|
+
const cmdPath = launcherCmdPath();
|
|
3660
|
+
await mkdir7(dirname7(cmdPath), { recursive: true });
|
|
3661
|
+
await ensureLogFiles();
|
|
3662
|
+
await writeFile6(cmdPath, buildLauncherCmd(), "utf8");
|
|
3663
|
+
}
|
|
3664
|
+
async function installSchtask() {
|
|
3665
|
+
await writeLauncherCmd();
|
|
3666
|
+
const create = runSchtasks([
|
|
3667
|
+
"/Create",
|
|
3668
|
+
"/F",
|
|
3669
|
+
"/SC",
|
|
3670
|
+
"ONLOGON",
|
|
3671
|
+
"/RL",
|
|
3672
|
+
"LIMITED",
|
|
3673
|
+
"/TN",
|
|
3674
|
+
WINDOWS_TASK_NAME,
|
|
3675
|
+
"/TR",
|
|
3676
|
+
`"${launcherCmdPath()}"`
|
|
3677
|
+
]);
|
|
3678
|
+
if (!create.ok) throw schtasksError("schtasks /Create", create);
|
|
3679
|
+
const run = runSchtasks(["/Run", "/TN", WINDOWS_TASK_NAME]);
|
|
3680
|
+
if (!run.ok) throw schtasksError("schtasks /Run", run);
|
|
3681
|
+
return statusSchtask();
|
|
3682
|
+
}
|
|
3683
|
+
async function uninstallSchtask() {
|
|
3684
|
+
runSchtasks(["/End", "/TN", WINDOWS_TASK_NAME]);
|
|
3685
|
+
const del = runSchtasks(["/Delete", "/F", "/TN", WINDOWS_TASK_NAME]);
|
|
3686
|
+
if (!del.ok && isTaskRegistered()) throw schtasksError("schtasks /Delete", del);
|
|
3687
|
+
if (existsSync5(launcherCmdPath())) await rm3(launcherCmdPath(), { force: true });
|
|
3688
|
+
}
|
|
3689
|
+
async function restartSchtask() {
|
|
3690
|
+
if (!isTaskRegistered()) {
|
|
3691
|
+
throw new Error(`\u8BA1\u5212\u4EFB\u52A1\u672A\u5B89\u88C5\uFF1A${WINDOWS_TASK_NAME}\uFF08\u5148\u8FD0\u884C \`feishu-codex-bridge start\`\uFF09`);
|
|
3692
|
+
}
|
|
3693
|
+
runSchtasks(["/End", "/TN", WINDOWS_TASK_NAME]);
|
|
3694
|
+
await waitUntilStopped();
|
|
3695
|
+
const run = runSchtasks(["/Run", "/TN", WINDOWS_TASK_NAME]);
|
|
3696
|
+
if (!run.ok) throw schtasksError("schtasks /Run", run);
|
|
3697
|
+
return statusSchtask();
|
|
3698
|
+
}
|
|
3699
|
+
function statusSchtask() {
|
|
3700
|
+
const installed = isTaskRegistered();
|
|
3701
|
+
const raw = installed ? describeTask() : "";
|
|
3702
|
+
return {
|
|
3703
|
+
platformName: "Task Scheduler (Windows)",
|
|
3704
|
+
installed,
|
|
3705
|
+
running: installed && /Status:\s+Running/i.test(raw),
|
|
3706
|
+
servicePath: WINDOWS_TASK_NAME,
|
|
3707
|
+
stdoutPath: serviceStdoutPath(),
|
|
3708
|
+
stderrPath: serviceStderrPath(),
|
|
3709
|
+
// `Process ID:` only appears in verbose output while the task is running.
|
|
3710
|
+
pid: raw.match(/Process ID:\s*(\d+)/i)?.[1],
|
|
3711
|
+
// `Last Result: 0` ⇒ last run succeeded. Surface it as the exit code.
|
|
3712
|
+
lastExit: raw.match(/Last Result:\s*(-?\d+)/i)?.[1],
|
|
3713
|
+
raw
|
|
3714
|
+
};
|
|
3715
|
+
}
|
|
3716
|
+
function isTaskRegistered() {
|
|
3717
|
+
const r = spawnSync2("schtasks", ["/Query", "/TN", WINDOWS_TASK_NAME], {
|
|
3718
|
+
stdio: ["ignore", "ignore", "ignore"]
|
|
3719
|
+
});
|
|
3720
|
+
return r.status === 0;
|
|
3721
|
+
}
|
|
3722
|
+
function schtaskRunning() {
|
|
3723
|
+
if (!isTaskRegistered()) return false;
|
|
3724
|
+
return /Status:\s+Running/i.test(describeTask());
|
|
3725
|
+
}
|
|
3726
|
+
function describeTask() {
|
|
3727
|
+
const r = runSchtasks(["/Query", "/V", "/FO", "LIST", "/TN", WINDOWS_TASK_NAME]);
|
|
3728
|
+
return r.stdout || r.stderr || "";
|
|
3729
|
+
}
|
|
3730
|
+
async function waitUntilStopped(timeoutMs = 5e3) {
|
|
3731
|
+
const deadline = Date.now() + timeoutMs;
|
|
3732
|
+
while (Date.now() < deadline) {
|
|
3733
|
+
if (!schtaskRunning()) return true;
|
|
3734
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
3735
|
+
}
|
|
3736
|
+
return false;
|
|
3737
|
+
}
|
|
3738
|
+
async function tailSchtaskLogs(follow) {
|
|
3739
|
+
await ensureLogFiles();
|
|
3740
|
+
const files = [serviceStdoutPath(), serviceStderrPath()];
|
|
3741
|
+
for (const f of files) {
|
|
3742
|
+
const tail = await lastLines(f, 100);
|
|
3743
|
+
if (tail) process.stdout.write(`
|
|
3744
|
+
===== ${f} =====
|
|
3745
|
+
${tail}
|
|
3746
|
+
`);
|
|
3747
|
+
}
|
|
3748
|
+
if (!follow) return;
|
|
3749
|
+
const offsets = new Map(files.map((f) => [f, fileSize(f)]));
|
|
3750
|
+
await new Promise((resolvePromise) => {
|
|
3751
|
+
const onSigint = () => {
|
|
3752
|
+
clearInterval(timer);
|
|
3753
|
+
process.off("SIGINT", onSigint);
|
|
3754
|
+
resolvePromise();
|
|
3755
|
+
};
|
|
3756
|
+
process.on("SIGINT", onSigint);
|
|
3757
|
+
const timer = setInterval(() => {
|
|
3758
|
+
for (const f of files) {
|
|
3759
|
+
const size = fileSize(f);
|
|
3760
|
+
const from = offsets.get(f) ?? 0;
|
|
3761
|
+
if (size > from) {
|
|
3762
|
+
offsets.set(f, size);
|
|
3763
|
+
createReadStream(f, { start: from, end: size - 1, encoding: "utf8" }).pipe(process.stdout, {
|
|
3764
|
+
end: false
|
|
3765
|
+
});
|
|
3766
|
+
} else if (size < from) {
|
|
3767
|
+
offsets.set(f, size);
|
|
3768
|
+
}
|
|
3769
|
+
}
|
|
3770
|
+
}, 700);
|
|
3771
|
+
});
|
|
3772
|
+
}
|
|
3773
|
+
function fileSize(file) {
|
|
3774
|
+
try {
|
|
3775
|
+
return statSync(file).size;
|
|
3776
|
+
} catch {
|
|
3777
|
+
return 0;
|
|
3778
|
+
}
|
|
3779
|
+
}
|
|
3780
|
+
async function lastLines(file, n) {
|
|
3781
|
+
try {
|
|
3782
|
+
const text = await readFile7(file, "utf8");
|
|
3783
|
+
const lines = text.split("\n");
|
|
3784
|
+
return lines.slice(-n - 1).join("\n").trimEnd();
|
|
3785
|
+
} catch {
|
|
3786
|
+
return "";
|
|
3787
|
+
}
|
|
3788
|
+
}
|
|
3789
|
+
|
|
3561
3790
|
// src/service/adapter.ts
|
|
3562
3791
|
function getServiceAdapter() {
|
|
3563
|
-
if (process.platform
|
|
3564
|
-
|
|
3792
|
+
if (process.platform === "darwin") {
|
|
3793
|
+
return {
|
|
3794
|
+
install: installLaunchd,
|
|
3795
|
+
uninstall: uninstallLaunchd,
|
|
3796
|
+
status: async () => statusLaunchd(),
|
|
3797
|
+
restart: restartLaunchd,
|
|
3798
|
+
logs: tailLaunchdLogs
|
|
3799
|
+
};
|
|
3565
3800
|
}
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3801
|
+
if (process.platform === "win32") {
|
|
3802
|
+
return {
|
|
3803
|
+
install: installSchtask,
|
|
3804
|
+
uninstall: uninstallSchtask,
|
|
3805
|
+
status: async () => statusSchtask(),
|
|
3806
|
+
restart: restartSchtask,
|
|
3807
|
+
logs: tailSchtaskLogs
|
|
3808
|
+
};
|
|
3809
|
+
}
|
|
3810
|
+
throw new Error(
|
|
3811
|
+
"service\uFF1A\u5F53\u524D\u5E73\u53F0\u6682\u4E0D\u652F\u6301\u540E\u53F0\u670D\u52A1\uFF08\u4EC5 macOS launchd / Windows \u8BA1\u5212\u4EFB\u52A1\uFF09\u3002\u8BF7\u7528 `feishu-codex-bridge run` \u524D\u53F0\u8FD0\u884C" + (process.platform === "linux" ? "\uFF1BLinux systemd \u652F\u6301\u540E\u7EED\u63D0\u4F9B\u3002" : "\u3002")
|
|
3812
|
+
);
|
|
3813
|
+
}
|
|
3814
|
+
function isServiceRunning() {
|
|
3815
|
+
try {
|
|
3816
|
+
if (process.platform === "darwin") return isLoaded();
|
|
3817
|
+
if (process.platform === "win32") return schtaskRunning();
|
|
3818
|
+
} catch {
|
|
3819
|
+
}
|
|
3820
|
+
return false;
|
|
3573
3821
|
}
|
|
3574
3822
|
|
|
3575
3823
|
// src/service/update.ts
|
|
3576
3824
|
var execFileP = promisify(execFile);
|
|
3577
3825
|
var NPM = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
3578
3826
|
function pkgRoot() {
|
|
3579
|
-
return
|
|
3827
|
+
return resolve5(dirname8(fileURLToPath4(import.meta.url)), "..");
|
|
3580
3828
|
}
|
|
3581
3829
|
function pkgJson() {
|
|
3582
3830
|
try {
|
|
3583
|
-
return JSON.parse(readFileSync2(
|
|
3831
|
+
return JSON.parse(readFileSync2(join10(pkgRoot(), "package.json"), "utf8"));
|
|
3584
3832
|
} catch {
|
|
3585
3833
|
return {};
|
|
3586
3834
|
}
|
|
@@ -3592,7 +3840,7 @@ function packageName() {
|
|
|
3592
3840
|
return pkgJson().name ?? "@modelzen/feishu-codex-bridge";
|
|
3593
3841
|
}
|
|
3594
3842
|
function isDevSource() {
|
|
3595
|
-
return
|
|
3843
|
+
return existsSync6(join10(pkgRoot(), ".git"));
|
|
3596
3844
|
}
|
|
3597
3845
|
function isNewer(a, b) {
|
|
3598
3846
|
const pa = a.split(".").map((n) => Number.parseInt(n, 10) || 0);
|
|
@@ -3615,7 +3863,7 @@ async function latestVersion() {
|
|
|
3615
3863
|
async function installLatest(opts = {}) {
|
|
3616
3864
|
const target = `${packageName()}@latest`;
|
|
3617
3865
|
return await new Promise((resolveP) => {
|
|
3618
|
-
const child =
|
|
3866
|
+
const child = spawn4(NPM, ["install", "-g", target], {
|
|
3619
3867
|
stdio: opts.inherit ? ["ignore", "inherit", "inherit"] : ["ignore", "pipe", "pipe"]
|
|
3620
3868
|
});
|
|
3621
3869
|
let out = "";
|
|
@@ -3631,20 +3879,16 @@ async function installLatest(opts = {}) {
|
|
|
3631
3879
|
});
|
|
3632
3880
|
}
|
|
3633
3881
|
function daemonRunning() {
|
|
3634
|
-
|
|
3635
|
-
return statusLaunchd().loaded;
|
|
3636
|
-
} catch {
|
|
3637
|
-
return false;
|
|
3638
|
-
}
|
|
3882
|
+
return isServiceRunning();
|
|
3639
3883
|
}
|
|
3640
3884
|
async function restartDaemon() {
|
|
3641
3885
|
await getServiceAdapter().restart();
|
|
3642
3886
|
}
|
|
3643
3887
|
|
|
3644
3888
|
// src/project/lifecycle.ts
|
|
3645
|
-
import { mkdir as
|
|
3646
|
-
import { existsSync as
|
|
3647
|
-
import { isAbsolute as isAbsolute2, join as
|
|
3889
|
+
import { mkdir as mkdir8 } from "fs/promises";
|
|
3890
|
+
import { existsSync as existsSync7 } from "fs";
|
|
3891
|
+
import { isAbsolute as isAbsolute2, join as join11, resolve as resolve6 } from "path";
|
|
3648
3892
|
|
|
3649
3893
|
// src/project/git-info.ts
|
|
3650
3894
|
import { execFile as execFile2 } from "child_process";
|
|
@@ -3779,12 +4023,12 @@ async function onboardGroup(channel, project) {
|
|
|
3779
4023
|
// src/project/lifecycle.ts
|
|
3780
4024
|
async function resolveCwd(name, existingPath) {
|
|
3781
4025
|
if (existingPath) {
|
|
3782
|
-
const cwd2 = isAbsolute2(existingPath) ? existingPath :
|
|
3783
|
-
if (!
|
|
4026
|
+
const cwd2 = isAbsolute2(existingPath) ? existingPath : resolve6(existingPath);
|
|
4027
|
+
if (!existsSync7(cwd2)) throw new Error(`\u6587\u4EF6\u5939\u4E0D\u5B58\u5728\uFF1A${cwd2}`);
|
|
3784
4028
|
return { cwd: cwd2, blank: false };
|
|
3785
4029
|
}
|
|
3786
|
-
const cwd =
|
|
3787
|
-
await
|
|
4030
|
+
const cwd = join11(paths.projectsRootDir, name);
|
|
4031
|
+
await mkdir8(cwd, { recursive: true });
|
|
3788
4032
|
return { cwd, blank: true };
|
|
3789
4033
|
}
|
|
3790
4034
|
async function createProject(channel, input2) {
|
|
@@ -3851,12 +4095,12 @@ async function leaveChat(channel, chatId) {
|
|
|
3851
4095
|
}
|
|
3852
4096
|
|
|
3853
4097
|
// src/bot/session-store.ts
|
|
3854
|
-
import { mkdir as
|
|
3855
|
-
import { dirname as
|
|
4098
|
+
import { mkdir as mkdir9, readFile as readFile8, rename as rename5, writeFile as writeFile7 } from "fs/promises";
|
|
4099
|
+
import { dirname as dirname9 } from "path";
|
|
3856
4100
|
var FILE_VERSION3 = 1;
|
|
3857
4101
|
async function read2() {
|
|
3858
4102
|
try {
|
|
3859
|
-
const text = await
|
|
4103
|
+
const text = await readFile8(paths.sessionsFile, "utf8");
|
|
3860
4104
|
const parsed = JSON.parse(text);
|
|
3861
4105
|
return Array.isArray(parsed.sessions) ? parsed.sessions : [];
|
|
3862
4106
|
} catch (err) {
|
|
@@ -3865,10 +4109,10 @@ async function read2() {
|
|
|
3865
4109
|
}
|
|
3866
4110
|
}
|
|
3867
4111
|
async function write2(sessions) {
|
|
3868
|
-
await
|
|
4112
|
+
await mkdir9(dirname9(paths.sessionsFile), { recursive: true });
|
|
3869
4113
|
const tmp = `${paths.sessionsFile}.tmp-${process.pid}`;
|
|
3870
4114
|
const body = { version: FILE_VERSION3, sessions };
|
|
3871
|
-
await
|
|
4115
|
+
await writeFile7(tmp, `${JSON.stringify(body, null, 2)}
|
|
3872
4116
|
`, "utf8");
|
|
3873
4117
|
await rename5(tmp, paths.sessionsFile);
|
|
3874
4118
|
}
|
|
@@ -3912,8 +4156,8 @@ async function handleDmConsole(channel, cfg, msg) {
|
|
|
3912
4156
|
}
|
|
3913
4157
|
|
|
3914
4158
|
// src/bot/media.ts
|
|
3915
|
-
import { mkdir as
|
|
3916
|
-
import { join as
|
|
4159
|
+
import { mkdir as mkdir10, readdir as readdir2, rm as rm4, stat as stat3 } from "fs/promises";
|
|
4160
|
+
import { join as join12 } from "path";
|
|
3917
4161
|
var MAX_IMAGES2 = 9;
|
|
3918
4162
|
var MEDIA_TTL_MS = 60 * 6e4;
|
|
3919
4163
|
var EXT_BY_CONTENT_TYPE = {
|
|
@@ -3942,7 +4186,7 @@ async function collectInboundImages(channel, msg) {
|
|
|
3942
4186
|
if (refs.length === 0) return [];
|
|
3943
4187
|
await pruneOldMedia();
|
|
3944
4188
|
try {
|
|
3945
|
-
await
|
|
4189
|
+
await mkdir10(paths.mediaDir, { recursive: true });
|
|
3946
4190
|
} catch {
|
|
3947
4191
|
}
|
|
3948
4192
|
const out = [];
|
|
@@ -4018,7 +4262,7 @@ async function downloadOne(channel, ref, index) {
|
|
|
4018
4262
|
params: { type: "image" }
|
|
4019
4263
|
});
|
|
4020
4264
|
const ext = extFromHeaders(res.headers);
|
|
4021
|
-
const file =
|
|
4265
|
+
const file = join12(paths.mediaDir, `${safeName(ref.fileKey)}-${index}.${ext}`);
|
|
4022
4266
|
await res.writeFile(file);
|
|
4023
4267
|
return file;
|
|
4024
4268
|
} catch (err) {
|
|
@@ -4052,10 +4296,10 @@ async function pruneOldMedia() {
|
|
|
4052
4296
|
}
|
|
4053
4297
|
const cutoff = Date.now() - MEDIA_TTL_MS;
|
|
4054
4298
|
for (const name of entries) {
|
|
4055
|
-
const file =
|
|
4299
|
+
const file = join12(paths.mediaDir, name);
|
|
4056
4300
|
try {
|
|
4057
4301
|
const st = await stat3(file);
|
|
4058
|
-
if (st.mtimeMs < cutoff) await
|
|
4302
|
+
if (st.mtimeMs < cutoff) await rm4(file, { force: true });
|
|
4059
4303
|
} catch {
|
|
4060
4304
|
}
|
|
4061
4305
|
}
|
|
@@ -5390,7 +5634,7 @@ async function startBridge(opts) {
|
|
|
5390
5634
|
|
|
5391
5635
|
// src/core/single-instance.ts
|
|
5392
5636
|
import { mkdirSync as mkdirSync2, readFileSync as readFileSync3, unlinkSync, writeFileSync } from "fs";
|
|
5393
|
-
import { dirname as
|
|
5637
|
+
import { dirname as dirname10 } from "path";
|
|
5394
5638
|
var BridgeAlreadyRunningError = class extends Error {
|
|
5395
5639
|
constructor(pid) {
|
|
5396
5640
|
super(
|
|
@@ -5419,7 +5663,7 @@ function acquireSingleInstanceLock(appId) {
|
|
|
5419
5663
|
} catch (err) {
|
|
5420
5664
|
if (err instanceof BridgeAlreadyRunningError) throw err;
|
|
5421
5665
|
}
|
|
5422
|
-
mkdirSync2(
|
|
5666
|
+
mkdirSync2(dirname10(file), { recursive: true });
|
|
5423
5667
|
const record = { pid: process.pid, appId, startedAt: Date.now() };
|
|
5424
5668
|
writeFileSync(file, `${JSON.stringify(record)}
|
|
5425
5669
|
`, "utf8");
|
|
@@ -5488,12 +5732,14 @@ async function runStart() {
|
|
|
5488
5732
|
return;
|
|
5489
5733
|
}
|
|
5490
5734
|
const status = await getServiceAdapter().install();
|
|
5491
|
-
console.log(
|
|
5735
|
+
console.log(
|
|
5736
|
+
process.platform === "win32" ? "\u2713 \u540E\u53F0\u670D\u52A1\u5DF2\u5B89\u88C5\u5E76\u542F\u52A8\uFF08\u767B\u5F55\u81EA\u542F\uFF1B\u6CE8\u610F\uFF1AWindows \u8BA1\u5212\u4EFB\u52A1\u65E0\u5D29\u6E83\u81EA\u52A8\u62C9\u8D77\uFF09\u3002" : "\u2713 \u540E\u53F0\u670D\u52A1\u5DF2\u5B89\u88C5\u5E76\u542F\u52A8\uFF08\u5F00\u673A\u81EA\u542F\u3001\u5D29\u6E83\u81EA\u52A8\u62C9\u8D77\uFF09\u3002"
|
|
5737
|
+
);
|
|
5492
5738
|
printStatus(status);
|
|
5493
5739
|
}
|
|
5494
5740
|
async function runStop() {
|
|
5495
5741
|
await getServiceAdapter().uninstall();
|
|
5496
|
-
console.log("\u2713 \u540E\u53F0\u670D\u52A1\u5DF2\u505C\u6B62\uFF0C\u5E76\u5DF2\u5173\u95ED\
|
|
5742
|
+
console.log("\u2713 \u540E\u53F0\u670D\u52A1\u5DF2\u505C\u6B62\uFF0C\u5E76\u5DF2\u5173\u95ED\u81EA\u542F\uFF08\u5DF2\u79FB\u9664\u670D\u52A1\u5B9A\u4E49\uFF09\u3002");
|
|
5497
5743
|
}
|
|
5498
5744
|
async function runRestart() {
|
|
5499
5745
|
const status = await getServiceAdapter().restart();
|
|
@@ -5507,17 +5753,18 @@ async function runLogs(follow) {
|
|
|
5507
5753
|
await getServiceAdapter().logs(follow);
|
|
5508
5754
|
}
|
|
5509
5755
|
function printStatus(status) {
|
|
5510
|
-
console.log(`
|
|
5756
|
+
console.log(`service: ${status.platformName}`);
|
|
5757
|
+
console.log(`path: ${status.servicePath}`);
|
|
5511
5758
|
console.log(`installed: ${status.installed ? "yes" : "no"}`);
|
|
5512
|
-
console.log(`
|
|
5759
|
+
console.log(`running: ${status.running ? "yes" : "no"}`);
|
|
5513
5760
|
console.log(`pid: ${status.pid ?? "-"}`);
|
|
5514
5761
|
console.log(`last exit: ${status.lastExit ?? "-"}`);
|
|
5515
5762
|
console.log(`stdout: ${status.stdoutPath}`);
|
|
5516
5763
|
console.log(`stderr: ${status.stderrPath}`);
|
|
5517
5764
|
if (!status.installed) {
|
|
5518
5765
|
console.log("\u63D0\u793A\uFF1A\u540E\u53F0\u670D\u52A1\u5C1A\u672A\u5B89\u88C5\uFF0C\u8FD0\u884C `feishu-codex-bridge start`\u3002");
|
|
5519
|
-
} else if (!status.
|
|
5520
|
-
console.log("\u63D0\u793A\
|
|
5766
|
+
} else if (!status.running) {
|
|
5767
|
+
console.log("\u63D0\u793A\uFF1A\u670D\u52A1\u5DF2\u6CE8\u518C\u4F46\u5F53\u524D\u672A\u8FD0\u884C\uFF08\u8BD5\u8BD5 `restart`\uFF09\u3002");
|
|
5521
5768
|
}
|
|
5522
5769
|
}
|
|
5523
5770
|
|
|
@@ -5570,7 +5817,7 @@ async function runUpdate(opts = {}) {
|
|
|
5570
5817
|
}
|
|
5571
5818
|
|
|
5572
5819
|
// src/cli/commands/bot.ts
|
|
5573
|
-
import { rm as
|
|
5820
|
+
import { rm as rm5 } from "fs/promises";
|
|
5574
5821
|
async function runBotInit(name) {
|
|
5575
5822
|
if (!ensureCodex()) {
|
|
5576
5823
|
process.exitCode = 1;
|
|
@@ -5625,7 +5872,7 @@ async function runBotRm(name) {
|
|
|
5625
5872
|
}
|
|
5626
5873
|
const after = await removeBot(bot2.appId);
|
|
5627
5874
|
await removeSecret(secretKeyForApp(bot2.appId));
|
|
5628
|
-
await
|
|
5875
|
+
await rm5(botDir(bot2.appId), { recursive: true, force: true });
|
|
5629
5876
|
console.log(`\u2713 \u5DF2\u79FB\u9664\u673A\u5668\u4EBA\u300C${bot2.name}\u300D(${bot2.appId})\uFF1A\u6CE8\u518C\u8868 + \u5BC6\u94A5 + \u72B6\u6001\u76EE\u5F55(projects/sessions)\u3002`);
|
|
5630
5877
|
if (after.bots.length === 0) {
|
|
5631
5878
|
console.log(" \u5DF2\u65E0\u4EFB\u4F55\u673A\u5668\u4EBA\uFF0C`bot init` \u91CD\u65B0\u521B\u5EFA\u3002");
|
|
@@ -5683,15 +5930,15 @@ async function secretsRemove(id) {
|
|
|
5683
5930
|
console.log(ok ? `\u2713 \u5DF2\u5220\u9664: ${id}` : `\u672A\u627E\u5230: ${id}`);
|
|
5684
5931
|
}
|
|
5685
5932
|
function readStdin() {
|
|
5686
|
-
return new Promise((
|
|
5933
|
+
return new Promise((resolve7) => {
|
|
5687
5934
|
let data = "";
|
|
5688
5935
|
if (process.stdin.isTTY) {
|
|
5689
|
-
|
|
5936
|
+
resolve7("");
|
|
5690
5937
|
return;
|
|
5691
5938
|
}
|
|
5692
5939
|
process.stdin.setEncoding("utf8");
|
|
5693
5940
|
process.stdin.on("data", (c) => data += c);
|
|
5694
|
-
process.stdin.on("end", () =>
|
|
5941
|
+
process.stdin.on("end", () => resolve7(data));
|
|
5695
5942
|
});
|
|
5696
5943
|
}
|
|
5697
5944
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@modelzen/feishu-codex-bridge",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1-win",
|
|
4
4
|
"description": "Bridge Feishu/Lark messenger with local Codex via app-server (project=group, thread=session)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -30,9 +30,11 @@
|
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@larksuiteoapi/node-sdk": "^1.65.0",
|
|
32
32
|
"commander": "^12.1.0",
|
|
33
|
+
"cross-spawn": "^7.0.6",
|
|
33
34
|
"qrcode-terminal": "^0.12.0"
|
|
34
35
|
},
|
|
35
36
|
"devDependencies": {
|
|
37
|
+
"@types/cross-spawn": "^6.0.6",
|
|
36
38
|
"@types/node": "^22.10.0",
|
|
37
39
|
"@types/qrcode-terminal": "^0.12.2",
|
|
38
40
|
"tsup": "^8.3.5",
|