dsh-lark-bot 0.7.0 → 0.8.0

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/plugin.d.ts CHANGED
@@ -113,6 +113,23 @@ interface RuntimeEnv {
113
113
  archiveMaxAgeDays: number;
114
114
  accessDefaultDeny: boolean;
115
115
  eventFreshnessMs: number;
116
+ /** Bridge engine heartbeat interval (guardian liveness signal), default 5000. */
117
+ heartbeatMs: number;
118
+ /** Guardian disabled switch (DSH_LARK_GUARDIAN_DISABLED=1 keeps it stopped). */
119
+ guardianDisabled: boolean;
120
+ /** dsh profile the guardian watches / relaunches (default `dsh-lark`). */
121
+ guardianProfile: string;
122
+ /** Bridge state profile providing Feishu credentials (default `default`). */
123
+ guardianBridgeProfile: string;
124
+ /** Guardian watchdog poll interval, default 2000. */
125
+ guardianPollMs: number;
126
+ /** Heartbeat staleness threshold before takeover, default 15000. */
127
+ guardianStaleMs: number;
128
+ /**
129
+ * When a dsh process is alive but the bridge heartbeat has been stale for
130
+ * longer than this, treat the engine as dead and take over (default 120000).
131
+ */
132
+ guardianEngineDeadMs: number;
116
133
  }
117
134
 
118
135
  interface ActiveRunHandle {
package/dist/plugin.js CHANGED
@@ -64,7 +64,7 @@ var init_dsh_compat = __esm({
64
64
  sdkServer: "0.1.0-rc.6",
65
65
  acp: "0.1.0-rc.6",
66
66
  node: ">=22.19.0",
67
- verifiedAt: "2026-08-14"
67
+ verifiedAt: "2026-08-15"
68
68
  };
69
69
  }
70
70
  });
@@ -4449,7 +4449,13 @@ var DEFAULTS = {
4449
4449
  scopeConcurrency: 2,
4450
4450
  retentionMsgs: 40,
4451
4451
  archiveMax: 50,
4452
- archiveMaxAgeDays: 90
4452
+ archiveMaxAgeDays: 90,
4453
+ heartbeatMs: 5e3,
4454
+ guardianPollMs: 2e3,
4455
+ guardianStaleMs: 15e3,
4456
+ guardianEngineDeadMs: 12e4,
4457
+ guardianProfile: "dsh-lark",
4458
+ guardianBridgeProfile: "default"
4453
4459
  };
4454
4460
  function nonEmpty(value) {
4455
4461
  const trimmed = value?.trim();
@@ -4535,6 +4541,15 @@ function parseMinOneInt(value, fallback, name2) {
4535
4541
  }
4536
4542
  return parsed;
4537
4543
  }
4544
+ function parsePositiveIntMin(value, fallback, name2) {
4545
+ const raw = value?.trim();
4546
+ if (!raw) return fallback;
4547
+ const parsed = Number(raw);
4548
+ if (!Number.isInteger(parsed) || parsed < 1) {
4549
+ throw new Error(`${name2} must be a positive integer, got "${raw}"`);
4550
+ }
4551
+ return parsed;
4552
+ }
4538
4553
  function loadRuntimeEnv(source = process.env) {
4539
4554
  const homeOverride = nonEmpty(source.DSH_LARK_HOME);
4540
4555
  const workspace = nonEmpty(source.DSH_LARK_WORKSPACE);
@@ -4585,7 +4600,30 @@ function loadRuntimeEnv(source = process.env) {
4585
4600
  "DSH_LARK_ARCHIVE_MAX_AGE_DAYS"
4586
4601
  ),
4587
4602
  accessDefaultDeny: parseBoolean(source.DSH_LARK_ACCESS_DEFAULT_DENY, false),
4588
- eventFreshnessMs: parseFreshness(source.DSH_LARK_EVENT_FRESHNESS_MS)
4603
+ eventFreshnessMs: parseFreshness(source.DSH_LARK_EVENT_FRESHNESS_MS),
4604
+ heartbeatMs: parsePositiveIntMin(
4605
+ source.DSH_LARK_HEARTBEAT_MS,
4606
+ DEFAULTS.heartbeatMs,
4607
+ "DSH_LARK_HEARTBEAT_MS"
4608
+ ),
4609
+ guardianDisabled: parseBoolean(source.DSH_LARK_GUARDIAN_DISABLED, false),
4610
+ guardianProfile: nonEmpty(source.DSH_LARK_GUARDIAN_PROFILE) ?? DEFAULTS.guardianProfile,
4611
+ guardianBridgeProfile: nonEmpty(source.DSH_LARK_GUARDIAN_BRIDGE_PROFILE) ?? DEFAULTS.guardianBridgeProfile,
4612
+ guardianPollMs: parsePositiveIntMin(
4613
+ source.DSH_LARK_GUARDIAN_POLL_MS,
4614
+ DEFAULTS.guardianPollMs,
4615
+ "DSH_LARK_GUARDIAN_POLL_MS"
4616
+ ),
4617
+ guardianStaleMs: parsePositiveIntMin(
4618
+ source.DSH_LARK_GUARDIAN_STALE_MS,
4619
+ DEFAULTS.guardianStaleMs,
4620
+ "DSH_LARK_GUARDIAN_STALE_MS"
4621
+ ),
4622
+ guardianEngineDeadMs: parsePositiveIntMin(
4623
+ source.DSH_LARK_GUARDIAN_ENGINE_DEAD_MS,
4624
+ DEFAULTS.guardianEngineDeadMs,
4625
+ "DSH_LARK_GUARDIAN_ENGINE_DEAD_MS"
4626
+ )
4589
4627
  };
4590
4628
  }
4591
4629
 
@@ -5315,6 +5353,36 @@ var WorkspaceStore = class {
5315
5353
  }
5316
5354
  };
5317
5355
 
5356
+ // src/guardian/heartbeat.ts
5357
+ import { readFile as readFile9 } from "fs/promises";
5358
+ var DEFAULT_HEARTBEAT_INTERVAL_MS = 5e3;
5359
+ function startHeartbeat(file, pid, intervalMs = DEFAULT_HEARTBEAT_INTERVAL_MS) {
5360
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
5361
+ let stopped = false;
5362
+ const beat = async () => {
5363
+ if (stopped) return;
5364
+ const payload = { pid, startedAt, ts: Date.now() };
5365
+ try {
5366
+ await writeFileAtomic(file, `${JSON.stringify(payload)}
5367
+ `, {
5368
+ mode: 384
5369
+ });
5370
+ } catch {
5371
+ }
5372
+ };
5373
+ void beat();
5374
+ const timer = setInterval(() => {
5375
+ void beat();
5376
+ }, intervalMs);
5377
+ timer.unref?.();
5378
+ return {
5379
+ stop() {
5380
+ stopped = true;
5381
+ clearInterval(timer);
5382
+ }
5383
+ };
5384
+ }
5385
+
5318
5386
  // src/cli/commands/run.ts
5319
5387
  var DEBOUNCE_MS = 600;
5320
5388
  async function ensureBotProfile(store, options) {
@@ -5520,6 +5588,11 @@ async function startBridgeEngine(options) {
5520
5588
  larkChannel = bridge.channel;
5521
5589
  await notifyServer.start();
5522
5590
  process.env.DSH_LARK_NOTIFY_URL = notifyServer.url ?? "";
5591
+ const heartbeat = startHeartbeat(
5592
+ paths.profilePath(profileName, "guardian", "heartbeat.json"),
5593
+ process.pid,
5594
+ env.heartbeatMs
5595
+ );
5523
5596
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
5524
5597
  log.info("cli", "started", {
5525
5598
  profile: profileName,
@@ -5544,6 +5617,7 @@ async function startBridgeEngine(options) {
5544
5617
  stop: async () => {
5545
5618
  if (stopped) return;
5546
5619
  stopped = true;
5620
+ heartbeat.stop();
5547
5621
  await notifyServer.stop();
5548
5622
  await bridge.disconnect();
5549
5623
  await adapter.dispose?.();