@modelzen/feishu-codex-bridge 0.4.0 → 0.4.2

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.
Files changed (2) hide show
  1. package/dist/cli.js +163 -95
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -2950,7 +2950,14 @@ function card(elements, opts = {}) {
2950
2950
  obj.header = {
2951
2951
  template: opts.header.template ?? "blue",
2952
2952
  title: { tag: "plain_text", content: opts.header.title },
2953
- ...opts.header.subtitle ? { subtitle: { tag: "plain_text", content: opts.header.subtitle } } : {}
2953
+ ...opts.header.subtitle ? { subtitle: { tag: "plain_text", content: opts.header.subtitle } } : {},
2954
+ ...opts.header.textTags?.length ? {
2955
+ text_tag_list: opts.header.textTags.map((t) => ({
2956
+ tag: "text_tag",
2957
+ text: { tag: "plain_text", content: t.text },
2958
+ color: t.color
2959
+ }))
2960
+ } : {}
2954
2961
  };
2955
2962
  }
2956
2963
  return obj;
@@ -3025,6 +3032,27 @@ function actions(items, elementId) {
3025
3032
  columns: items.map((it) => ({ tag: "column", width: "auto", elements: [it] }))
3026
3033
  };
3027
3034
  }
3035
+ function actionsFixed(items, width, elementId) {
3036
+ return {
3037
+ tag: "column_set",
3038
+ ...elementId ? { element_id: elementId } : {},
3039
+ flex_mode: "flow",
3040
+ horizontal_spacing: "8px",
3041
+ columns: items.map((it) => ({ tag: "column", width: "auto", elements: [{ ...it, width, size: "large" }] }))
3042
+ };
3043
+ }
3044
+ function splitRow(left, right, elementId) {
3045
+ return {
3046
+ tag: "column_set",
3047
+ ...elementId ? { element_id: elementId } : {},
3048
+ flex_mode: "none",
3049
+ horizontal_spacing: "medium",
3050
+ columns: [
3051
+ { tag: "column", width: "auto", vertical_align: "center", elements: [left] },
3052
+ { tag: "column", width: "weighted", weight: 1, vertical_align: "center", elements: [right] }
3053
+ ]
3054
+ };
3055
+ }
3028
3056
  function button(label, value, type = "default") {
3029
3057
  return {
3030
3058
  tag: "button",
@@ -3033,11 +3061,12 @@ function button(label, value, type = "default") {
3033
3061
  behaviors: [{ type: "callback", value }]
3034
3062
  };
3035
3063
  }
3036
- function linkButton(label, url, type = "default") {
3064
+ function linkButton(label, url, type = "default", size) {
3037
3065
  return {
3038
3066
  tag: "button",
3039
3067
  text: { tag: "plain_text", content: label },
3040
3068
  type,
3069
+ ...size ? { size } : {},
3041
3070
  behaviors: [{ type: "open_url", default_url: url }]
3042
3071
  };
3043
3072
  }
@@ -3295,6 +3324,8 @@ function openChatUrl(chatId) {
3295
3324
  return `https://applink.feishu.cn/client/chat/open?openChatId=${encodeURIComponent(chatId)}`;
3296
3325
  }
3297
3326
  var REPO = "https://github.com/modelzen/feishu-codex-bridge";
3327
+ var MENU_BTN_W_TOP = "152px";
3328
+ var MENU_BTN_W_BOT = "112px";
3298
3329
  var DM = {
3299
3330
  menu: "dm.menu",
3300
3331
  newProject: "dm.newProject",
@@ -3351,24 +3382,47 @@ var GS = {
3351
3382
  function kindLabel(kind) {
3352
3383
  return kind === "single" ? "\u{1F4AC} \u5355\u4F1A\u8BDD\u7FA4" : "\u{1F465} \u591A\u8BDD\u9898\u7FA4";
3353
3384
  }
3354
- function buildDmMenuCard() {
3385
+ function buildDmMenuCard(opts = {}) {
3386
+ const { webConsoleUrl: webConsoleUrl2, version } = opts;
3355
3387
  return card(
3356
3388
  [
3357
3389
  md("\u79C1\u804A\u7528\u4E8E**\u5EFA\u9879\u76EE\u548C\u7BA1\u7406**\uFF1B\u5177\u4F53\u4EFB\u52A1\u8BF7\u5230\u9879\u76EE\u7FA4\u91CC @\u6211\u3002"),
3358
3390
  hr(),
3359
- actions([
3391
+ // 两行按钮固定宽度、左对齐;两行宽度配平后总长相等、右边缘对齐(见 MENU_BTN_W_*)。
3392
+ actionsFixed([
3360
3393
  button("\u2795 \u65B0\u5EFA\u9879\u76EE", { a: DM.newProject }, "primary"),
3361
3394
  button("\u{1F4C1} \u9879\u76EE\u5217\u8868", { a: DM.projects }),
3362
3395
  button("\u2699\uFE0F \u8BBE\u7F6E", { a: DM.settings })
3363
- ]),
3364
- actions([
3396
+ ], MENU_BTN_W_TOP),
3397
+ actionsFixed([
3365
3398
  button("\u{1F4CA} \u7528\u91CF", { a: DM.usage }),
3366
3399
  button("\u{1FA7A} \u8BCA\u65AD", { a: DM.doctor }),
3367
3400
  button("\u{1F504} \u91CD\u8FDE", { a: DM.reconnect }),
3368
- button("\u2B06\uFE0F \u7248\u672C\u66F4\u65B0", { a: DM.update })
3369
- ])
3401
+ button("\u2B06\uFE0F \u66F4\u65B0", { a: DM.update })
3402
+ ], MENU_BTN_W_BOT),
3403
+ // 🌐 网页控制台:刻意低调——小号按钮靠左 + 右侧灰字说明;仅在 daemon 本机控制台
3404
+ // 在跑(webConsoleUrl 有值)时出现。按钮直接开 127.0.0.1 控制台——只有运行 bridge
3405
+ // 的这台机器打得开;其它电脑/手机点了会打不开(本机回环地址,飞书也分不出点击设备
3406
+ // 是不是本机),右侧文字已说明,按用户决定不另做处理。
3407
+ ...webConsoleUrl2 ? [
3408
+ hr(),
3409
+ splitRow(
3410
+ linkButton("\u{1F310} \u7F51\u9875\u63A7\u5236\u53F0", webConsoleUrl2, "default", "small"),
3411
+ note("\u4EC5\u5728**\u8FD0\u884C bridge \u7684\u8FD9\u53F0\u7535\u8111**\u4E0A\u80FD\u6253\u5F00\uFF08\u672C\u673A\u5730\u5740\uFF09\u3002")
3412
+ )
3413
+ ] : []
3370
3414
  ],
3371
- { header: { title: "\u{1F916} Codex Bridge \u7BA1\u7406\u53F0", template: "blue" } }
3415
+ {
3416
+ header: {
3417
+ title: "\u{1F916} Codex Bridge \u7BA1\u7406\u53F0",
3418
+ template: "blue",
3419
+ textTags: version ? [{ text: `v${version}`, color: "green" }] : void 0
3420
+ },
3421
+ // 这张卡可能内嵌带 token 的本机控制台直达链接(pc_url),且按钮全是管理员专属的
3422
+ // dm.* 回调——转发出去既无意义、又会把 token 链接一并带走。loopback 已使转发副本
3423
+ // 在他人设备上不可用,这里再加一道:禁止转发。
3424
+ forward: false
3425
+ }
3372
3426
  );
3373
3427
  }
3374
3428
  var backToMenu = () => actions([button("\u2B05\uFE0F \u83DC\u5355", { a: DM.menu })]);
@@ -6751,6 +6805,71 @@ function buildUsageShareCard(data, opts = {}) {
6751
6805
  });
6752
6806
  }
6753
6807
 
6808
+ // src/web/discovery.ts
6809
+ import { randomUUID as randomUUID3 } from "crypto";
6810
+ import { mkdirSync as mkdirSync2, readFileSync as readFileSync5, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
6811
+ import { dirname as dirname10 } from "path";
6812
+ function publishWebConsole(rec, file = paths.webConsoleFile) {
6813
+ mkdirSync2(dirname10(file), { recursive: true });
6814
+ try {
6815
+ unlinkSync(file);
6816
+ } catch {
6817
+ }
6818
+ writeFileSync2(file, `${JSON.stringify(rec, null, 2)}
6819
+ `, { mode: 384 });
6820
+ }
6821
+ function readWebConsole(file = paths.webConsoleFile) {
6822
+ try {
6823
+ const rec = JSON.parse(readFileSync5(file, "utf8"));
6824
+ if (typeof rec.port !== "number" || typeof rec.token !== "string" || rec.token === "" || typeof rec.pid !== "number") {
6825
+ return void 0;
6826
+ }
6827
+ if (!isAlive(rec.pid)) return void 0;
6828
+ return rec;
6829
+ } catch {
6830
+ return void 0;
6831
+ }
6832
+ }
6833
+ function webConsoleUrl(file = paths.webConsoleFile) {
6834
+ const rec = readWebConsole(file);
6835
+ if (!rec) return void 0;
6836
+ return `http://127.0.0.1:${rec.port}/?token=${encodeURIComponent(rec.token)}`;
6837
+ }
6838
+ function clearWebConsole(file = paths.webConsoleFile) {
6839
+ try {
6840
+ const rec = JSON.parse(readFileSync5(file, "utf8"));
6841
+ if (rec.pid === process.pid) unlinkSync(file);
6842
+ } catch {
6843
+ }
6844
+ }
6845
+ function stableWebConsoleToken(file = paths.webTokenFile) {
6846
+ try {
6847
+ const t = readFileSync5(file, "utf8").trim();
6848
+ if (t) return t;
6849
+ } catch {
6850
+ }
6851
+ const token = randomUUID3();
6852
+ try {
6853
+ mkdirSync2(dirname10(file), { recursive: true });
6854
+ try {
6855
+ unlinkSync(file);
6856
+ } catch {
6857
+ }
6858
+ writeFileSync2(file, `${token}
6859
+ `, { mode: 384 });
6860
+ } catch {
6861
+ }
6862
+ return token;
6863
+ }
6864
+ function isAlive(pid) {
6865
+ try {
6866
+ process.kill(pid, 0);
6867
+ return true;
6868
+ } catch (err) {
6869
+ return err.code === "EPERM";
6870
+ }
6871
+ }
6872
+
6754
6873
  // src/project/lifecycle.ts
6755
6874
  import { mkdir as mkdir10 } from "fs/promises";
6756
6875
  import { existsSync as existsSync9 } from "fs";
@@ -7019,8 +7138,8 @@ async function leaveChat(channel, chatId) {
7019
7138
 
7020
7139
  // src/bot/session-store.ts
7021
7140
  import { mkdir as mkdir11, readFile as readFile10, rename as rename5, writeFile as writeFile9 } from "fs/promises";
7022
- import { randomUUID as randomUUID3 } from "crypto";
7023
- import { dirname as dirname10 } from "path";
7141
+ import { randomUUID as randomUUID4 } from "crypto";
7142
+ import { dirname as dirname11 } from "path";
7024
7143
  var FILE_VERSION3 = 2;
7025
7144
  var LEGACY_V1_SESSION_FIELD = "codexThreadId";
7026
7145
  function migrate(raw) {
@@ -7056,8 +7175,8 @@ function withLock2(fn) {
7056
7175
  return run;
7057
7176
  }
7058
7177
  async function write2(sessions) {
7059
- await mkdir11(dirname10(paths.sessionsFile), { recursive: true });
7060
- const tmp = `${paths.sessionsFile}.tmp-${process.pid}-${randomUUID3()}`;
7178
+ await mkdir11(dirname11(paths.sessionsFile), { recursive: true });
7179
+ const tmp = `${paths.sessionsFile}.tmp-${process.pid}-${randomUUID4()}`;
7061
7180
  const body = { version: FILE_VERSION3, sessions };
7062
7181
  await writeFile9(tmp, `${JSON.stringify(body, null, 2)}
7063
7182
  `, "utf8");
@@ -7101,7 +7220,7 @@ async function handleDmConsole(channel, cfg, msg) {
7101
7220
  await channel.send(msg.chatId, { markdown: "\u26D4 \u4EC5\u7BA1\u7406\u5458\u53EF\u5728\u79C1\u804A\u91CC\u7BA1\u7406\u9879\u76EE\u3002" }, { replyTo: msg.messageId }).catch(() => void 0);
7102
7221
  return;
7103
7222
  }
7104
- await sendManagedCard(channel, msg.chatId, buildDmMenuCard(), msg.messageId).catch(
7223
+ await sendManagedCard(channel, msg.chatId, buildDmMenuCard({ webConsoleUrl: webConsoleUrl(), version: bridgeVersion() }), msg.messageId).catch(
7105
7224
  (err) => log.fail("console", err, { cmd: "menu-send" })
7106
7225
  );
7107
7226
  });
@@ -7502,6 +7621,12 @@ function sanitizeContext(s, maxLen, oneLine2) {
7502
7621
  out = out.trim();
7503
7622
  return out.length > maxLen ? `${out.slice(0, maxLen)}\u2026` : out;
7504
7623
  }
7624
+ function prependBlock(block, text) {
7625
+ const base = text.trim();
7626
+ return base ? `${block}
7627
+
7628
+ ${base}` : block;
7629
+ }
7505
7630
  function weaveQuote(text, quoted) {
7506
7631
  if (!quoted) return text;
7507
7632
  const who = sanitizeContext(quoted.senderName, 40, true) || "\u67D0\u4EBA";
@@ -7510,10 +7635,7 @@ function weaveQuote(text, quoted) {
7510
7635
  const block = `[\u7528\u6237\u5F15\u7528\u4E86\u4E00\u6761\u6D88\u606F\uFF08\u6765\u81EA ${who}\uFF09\uFF1A
7511
7636
  ${body}
7512
7637
  ]`;
7513
- const base = text.trim();
7514
- return base ? `${block}
7515
-
7516
- ${base}` : block;
7638
+ return prependBlock(block, text);
7517
7639
  }
7518
7640
  function weaveThreadHistory(text, msgs) {
7519
7641
  if (msgs.length === 0) return text;
@@ -7526,10 +7648,15 @@ function weaveThreadHistory(text, msgs) {
7526
7648
  const block = `[\u8BDD\u9898\u4E2D\u5728\u6B64\u4E4B\u524D\u5DF2\u6709\u7684\u6D88\u606F\uFF08\u6309\u65F6\u95F4\u5148\u540E\u6392\u5217\uFF0C\u4F9B\u4F60\u7406\u89E3\u4E0A\u4E0B\u6587\uFF09\uFF1A
7527
7649
  ${lines.join("\n")}
7528
7650
  ]`;
7529
- const base = text.trim();
7530
- return base ? `${block}
7531
-
7532
- ${base}` : block;
7651
+ return prependBlock(block, text);
7652
+ }
7653
+ var SENDER_NAME_MAX = 40;
7654
+ function weaveSender(text, sender) {
7655
+ const id = (sender.senderId ?? "").trim();
7656
+ if (!id) return text;
7657
+ const who = sanitizeContext(sender.senderName ?? "", SENDER_NAME_MAX, true) || "\u67D0\u7528\u6237";
7658
+ const block = `[\u672C\u6761\u6D88\u606F\u7684\u53D1\u4FE1\u4EBA\uFF1A${who}\uFF08open_id\uFF1A${id}\uFF09]`;
7659
+ return prependBlock(block, text);
7533
7660
  }
7534
7661
 
7535
7662
  // src/bot/comments.ts
@@ -8271,6 +8398,7 @@ function createOrchestrator(channel, cfg, fallbackCwd) {
8271
8398
  const quoted = await fetchQuotedMessage(channel, msg.replyToMessageId);
8272
8399
  body = weaveQuote(body, quoted);
8273
8400
  }
8401
+ body = weaveSender(body, msg);
8274
8402
  return body;
8275
8403
  }
8276
8404
  async function handleTurn(msg, text, sessionKey, flat, project, perm) {
@@ -8854,7 +8982,7 @@ function createOrchestrator(channel, cfg, fallbackCwd) {
8854
8982
  patch(evt, buildSettingsCard(cfg));
8855
8983
  }
8856
8984
  const freshMenu = (evt) => {
8857
- patch(evt, buildDmMenuCard());
8985
+ patch(evt, buildDmMenuCard({ webConsoleUrl: webConsoleUrl(), version: bridgeVersion() }));
8858
8986
  };
8859
8987
  const runUsage = (evt, force) => {
8860
8988
  if (!dmAdmin(evt.operator?.openId)) return;
@@ -9204,7 +9332,7 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
9204
9332
  const name = typeof value.n === "string" ? value.n : "";
9205
9333
  patch(evt, async () => {
9206
9334
  const p = await getProjectByName(name);
9207
- if (!p) return buildDmMenuCard();
9335
+ if (!p) return buildDmMenuCard({ webConsoleUrl: webConsoleUrl(), version: bridgeVersion() });
9208
9336
  return buildAllowlistCard(p, await namesWithOperator(evt, p.allowedUsers ?? []));
9209
9337
  });
9210
9338
  }).on(DM.addAllowedForm, ({ evt, value }) => {
@@ -9236,7 +9364,7 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
9236
9364
  patch(evt, async () => {
9237
9365
  await updateProject(name, (p) => ({ allowedUsers: (p.allowedUsers ?? []).filter((x) => x !== id) }));
9238
9366
  const fresh = await getProjectByName(name);
9239
- if (!fresh) return buildDmMenuCard();
9367
+ if (!fresh) return buildDmMenuCard({ webConsoleUrl: webConsoleUrl(), version: bridgeVersion() });
9240
9368
  return buildAllowlistCard(fresh, await namesWithOperator(evt, fresh.allowedUsers ?? []));
9241
9369
  });
9242
9370
  }).on(DM.projectSettings, ({ evt, value }) => {
@@ -9244,14 +9372,14 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
9244
9372
  const name = typeof value.n === "string" ? value.n : "";
9245
9373
  patch(evt, async () => {
9246
9374
  const p = await getProjectByName(name);
9247
- return p ? buildProjectSettingsCard(p, backendDisplayName(p.backend)) : buildDmMenuCard();
9375
+ return p ? buildProjectSettingsCard(p, backendDisplayName(p.backend)) : buildDmMenuCard({ webConsoleUrl: webConsoleUrl(), version: bridgeVersion() });
9248
9376
  });
9249
9377
  }).on(DM.projectTopics, ({ evt, value }) => {
9250
9378
  if (!dmAdmin(evt.operator?.openId)) return;
9251
9379
  const name = typeof value.n === "string" ? value.n : "";
9252
9380
  patch(evt, async () => {
9253
9381
  const p = await getProjectByName(name);
9254
- if (!p) return buildDmMenuCard();
9382
+ if (!p) return buildDmMenuCard({ webConsoleUrl: webConsoleUrl(), version: bridgeVersion() });
9255
9383
  const sessions2 = (await listSessions()).filter((s) => s.chatId === p.chatId);
9256
9384
  return buildProjectTopicsCard(p, sessions2);
9257
9385
  });
@@ -9261,7 +9389,7 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
9261
9389
  const on = value.v === "on";
9262
9390
  patch(evt, async () => {
9263
9391
  const r = await performSetNoMention({ projectName: name, on });
9264
- if (!r.ok) return buildDmMenuCard();
9392
+ if (!r.ok) return buildDmMenuCard({ webConsoleUrl: webConsoleUrl(), version: bridgeVersion() });
9265
9393
  return buildProjectSettingsCard(r.project, backendDisplayName(r.project.backend));
9266
9394
  });
9267
9395
  }).on(DM.setAutoCompactDm, ({ evt, value }) => {
@@ -9270,7 +9398,7 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
9270
9398
  const on = value.v === "on";
9271
9399
  patch(evt, async () => {
9272
9400
  const r = await performSetAutoCompact({ projectName: name, on, evictLiveSessionsForChat });
9273
- if (!r.ok) return buildDmMenuCard();
9401
+ if (!r.ok) return buildDmMenuCard({ webConsoleUrl: webConsoleUrl(), version: bridgeVersion() });
9274
9402
  log.info("console", "project-autocompact", { project: name, on });
9275
9403
  return buildProjectSettingsCard(r.project, backendDisplayName(r.project.backend));
9276
9404
  });
@@ -9279,7 +9407,7 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
9279
9407
  const name = typeof value.n === "string" ? value.n : "";
9280
9408
  patch(evt, async () => {
9281
9409
  const p = await getProjectByName(name);
9282
- return p ? buildPermissionCard(p) : buildDmMenuCard();
9410
+ return p ? buildPermissionCard(p) : buildDmMenuCard({ webConsoleUrl: webConsoleUrl(), version: bridgeVersion() });
9283
9411
  });
9284
9412
  }).on(DM.permissionSubmit, ({ evt, value, formValue }) => {
9285
9413
  if (!dmAdmin(evt.operator?.openId)) return;
@@ -10080,7 +10208,7 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
10080
10208
  }).catch(() => void 0);
10081
10209
  return;
10082
10210
  }
10083
- await sendManagedCard(channel, op, buildDmMenuCard(), void 0, false, "open_id").catch(
10211
+ await sendManagedCard(channel, op, buildDmMenuCard({ webConsoleUrl: webConsoleUrl(), version: bridgeVersion() }), void 0, false, "open_id").catch(
10084
10212
  (err) => log.fail("console", err, { cmd: "menu-card" })
10085
10213
  );
10086
10214
  };
@@ -10346,7 +10474,7 @@ function withOwnerAdmin(base, ownerOpenId) {
10346
10474
 
10347
10475
  // src/admin/host.ts
10348
10476
  import { readdir as readdir4, stat as stat4 } from "fs/promises";
10349
- import { dirname as dirname11, join as join18, resolve as resolve7 } from "path";
10477
+ import { dirname as dirname12, join as join18, resolve as resolve7 } from "path";
10350
10478
  import { fileURLToPath as fileURLToPath5 } from "url";
10351
10479
  import { arch, platform as platform2, release } from "os";
10352
10480
  function toDaemonStatus(opts) {
@@ -10398,7 +10526,7 @@ async function collectHostDoctor(logsDir2 = join18(paths.appDir, "logs")) {
10398
10526
  };
10399
10527
  }
10400
10528
  function resolveCliBinPath3() {
10401
- const distDir = dirname11(fileURLToPath5(import.meta.url));
10529
+ const distDir = dirname12(fileURLToPath5(import.meta.url));
10402
10530
  return resolve7(distDir, "..", "bin", "feishu-codex-bridge.mjs");
10403
10531
  }
10404
10532
  function buildDaemonControlCommand(action, binPath = resolveCliBinPath3(), nodePath = process.execPath) {
@@ -10448,7 +10576,7 @@ function createAdminService(deps = {}) {
10448
10576
  try {
10449
10577
  const raw = await readFile11(botPaths(botId).processesFile, "utf8");
10450
10578
  const rec = JSON.parse(raw);
10451
- if (typeof rec.pid === "number" && isAlive(rec.pid)) {
10579
+ if (typeof rec.pid === "number" && isAlive2(rec.pid)) {
10452
10580
  return { running: true, pid: rec.pid, startedAt: rec.startedAt };
10453
10581
  }
10454
10582
  } catch {
@@ -10844,7 +10972,7 @@ async function probeAllBackends() {
10844
10972
  function createReadonlyAdminService(deps = {}) {
10845
10973
  return createAdminService({ startDaemon: deps.startDaemon, applyUpdate: deps.applyUpdate, readonlyPreview: true });
10846
10974
  }
10847
- function isAlive(pid) {
10975
+ function isAlive2(pid) {
10848
10976
  try {
10849
10977
  process.kill(pid, 0);
10850
10978
  return true;
@@ -10853,66 +10981,6 @@ function isAlive(pid) {
10853
10981
  }
10854
10982
  }
10855
10983
 
10856
- // src/web/discovery.ts
10857
- import { randomUUID as randomUUID4 } from "crypto";
10858
- import { mkdirSync as mkdirSync2, readFileSync as readFileSync5, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
10859
- import { dirname as dirname12 } from "path";
10860
- function publishWebConsole(rec, file = paths.webConsoleFile) {
10861
- mkdirSync2(dirname12(file), { recursive: true });
10862
- try {
10863
- unlinkSync(file);
10864
- } catch {
10865
- }
10866
- writeFileSync2(file, `${JSON.stringify(rec, null, 2)}
10867
- `, { mode: 384 });
10868
- }
10869
- function readWebConsole(file = paths.webConsoleFile) {
10870
- try {
10871
- const rec = JSON.parse(readFileSync5(file, "utf8"));
10872
- if (typeof rec.port !== "number" || typeof rec.token !== "string" || rec.token === "" || typeof rec.pid !== "number") {
10873
- return void 0;
10874
- }
10875
- if (!isAlive2(rec.pid)) return void 0;
10876
- return rec;
10877
- } catch {
10878
- return void 0;
10879
- }
10880
- }
10881
- function clearWebConsole(file = paths.webConsoleFile) {
10882
- try {
10883
- const rec = JSON.parse(readFileSync5(file, "utf8"));
10884
- if (rec.pid === process.pid) unlinkSync(file);
10885
- } catch {
10886
- }
10887
- }
10888
- function stableWebConsoleToken(file = paths.webTokenFile) {
10889
- try {
10890
- const t = readFileSync5(file, "utf8").trim();
10891
- if (t) return t;
10892
- } catch {
10893
- }
10894
- const token = randomUUID4();
10895
- try {
10896
- mkdirSync2(dirname12(file), { recursive: true });
10897
- try {
10898
- unlinkSync(file);
10899
- } catch {
10900
- }
10901
- writeFileSync2(file, `${token}
10902
- `, { mode: 384 });
10903
- } catch {
10904
- }
10905
- return token;
10906
- }
10907
- function isAlive2(pid) {
10908
- try {
10909
- process.kill(pid, 0);
10910
- return true;
10911
- } catch (err) {
10912
- return err.code === "EPERM";
10913
- }
10914
- }
10915
-
10916
10984
  // src/cli/commands/daemon-control.ts
10917
10985
  function spawnDaemonControl(action) {
10918
10986
  const { command, args } = buildDaemonControlCommand(action);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@modelzen/feishu-codex-bridge",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "Bridge Feishu/Lark messenger with local Codex via app-server (project=group, thread=session)",
5
5
  "type": "module",
6
6
  "bin": {