dsh-lark-bot 0.19.14 → 0.19.16

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/README.md CHANGED
@@ -113,7 +113,7 @@ dsh --profile dsh-lark # ② 启动
113
113
 
114
114
  ## 兼容性
115
115
 
116
- - **DeepSeek Harness(`dsh`)**:已验证 **0.1.0-rc.8**(2026-08-22),经官方 `@deepseek-ai/dsh-sdk-client` / `dsh-acp` 接入;锁定版本与升级政策见 [`docs/COMPATIBILITY.md`](docs/COMPATIBILITY.md)。
116
+ - **DeepSeek Harness(`dsh`)**:已验证 **0.1.0-rc.8**(2026-08-25),经官方 `@deepseek-ai/dsh-sdk-client` / `dsh-acp` 接入;锁定版本与升级政策见 [`docs/COMPATIBILITY.md`](docs/COMPATIBILITY.md)。
117
117
  - **运行时**:Node.js ≥ 22.19;**平台**:Linux / macOS / Windows。adapter 默认 `sdk`(原生续跑 / 流式 / 图片块),可切 `acp` / `headless` / `web`。
118
118
 
119
119
  ## 配置说明
package/README_EN.md CHANGED
@@ -114,7 +114,7 @@ Command help, status, and cards are bilingual; `/help` is the full authoritative
114
114
 
115
115
  ## Compatibility
116
116
 
117
- - **DeepSeek Harness (`dsh`)**: verified against **0.1.0-rc.8** (2026-08-22) via the official `@deepseek-ai/dsh-sdk-client` / `dsh-acp`; locked versions & upgrade policy in [`docs/COMPATIBILITY.md`](docs/COMPATIBILITY.md).
117
+ - **DeepSeek Harness (`dsh`)**: verified against **0.1.0-rc.8** (2026-08-25) via the official `@deepseek-ai/dsh-sdk-client` / `dsh-acp`; locked versions & upgrade policy in [`docs/COMPATIBILITY.md`](docs/COMPATIBILITY.md).
118
118
  - **Runtime**: Node.js ≥ 22.19; **Platforms**: Linux / macOS / Windows. Default adapter `sdk` (native resume / streaming / image blocks); switchable to `acp` / `headless` / `web`.
119
119
 
120
120
  ## Configuration
package/dist/cli.js CHANGED
@@ -129,7 +129,7 @@ var init_dsh_compat = __esm({
129
129
  sdkServer: "0.1.0-rc.8",
130
130
  acp: "0.1.0-rc.8",
131
131
  node: ">=22.19.0",
132
- verifiedAt: "2026-08-22"
132
+ verifiedAt: "2026-08-25"
133
133
  };
134
134
  }
135
135
  });
@@ -3706,6 +3706,7 @@ var DEFAULTS = {
3706
3706
  tenant: "feishu",
3707
3707
  provider: "",
3708
3708
  model: "",
3709
+ imageMaxDimension: 2e3,
3709
3710
  runTimeoutMs: 3e5,
3710
3711
  stopGraceMs: 5e3,
3711
3712
  groupPollMs: 3e3,
@@ -3889,6 +3890,11 @@ function loadRuntimeEnv(source = process.env) {
3889
3890
  provider: nonEmpty(source.DSH_LARK_PROVIDER) ?? DEFAULTS.provider,
3890
3891
  model: nonEmpty(source.DSH_LARK_MODEL) ?? DEFAULTS.model,
3891
3892
  maxTokens: parseMaxTokens(source.DSH_LARK_MAX_TOKENS),
3893
+ imageMaxDimension: parseMinOneInt(
3894
+ source.DSH_LARK_IMAGE_MAX_DIMENSION,
3895
+ DEFAULTS.imageMaxDimension,
3896
+ "DSH_LARK_IMAGE_MAX_DIMENSION"
3897
+ ),
3892
3898
  runTimeoutMs: parseTimeout(source.DSH_LARK_RUN_TIMEOUT_MS),
3893
3899
  stopGraceMs: parseStopGrace(source.DSH_LARK_STOP_GRACE_MS),
3894
3900
  groupNoAt: parseBoolean(source.DSH_LARK_GROUP_NO_AT, false),
@@ -6190,7 +6196,7 @@ async function runDoctor(options) {
6190
6196
 
6191
6197
  // src/cli/commands/run.ts
6192
6198
  import { mkdir as mkdir22 } from "fs/promises";
6193
- import { randomUUID as randomUUID15 } from "crypto";
6199
+ import { randomUUID as randomUUID16 } from "crypto";
6194
6200
  import { join as join27 } from "path";
6195
6201
 
6196
6202
  // src/bot/active-runs.ts
@@ -11229,6 +11235,9 @@ function abortError() {
11229
11235
  return error;
11230
11236
  }
11231
11237
 
11238
+ // src/onboard/sink-qr-providers.ts
11239
+ import { createDecipheriv, randomBytes as randomBytes2, randomUUID as randomUUID8 } from "crypto";
11240
+
11232
11241
  // src/notify/sinks/text.ts
11233
11242
  function renderSinkText(message) {
11234
11243
  const zhLine = `${message.title.zh}\uFF08scope \`${message.scope}\`\uFF09${message.detail ? `\uFF1A${message.detail}` : ""}`;
@@ -11310,63 +11319,131 @@ function splitDestination(value) {
11310
11319
  }
11311
11320
 
11312
11321
  // src/onboard/sink-qr-providers.ts
11313
- var WeChatQrProvider = class {
11314
- constructor(baseUrl = process.env.DSH_LARK_WECHAT_ILINK_URL ?? "https://ilinkai.weixin.qq.com", fetchImpl = fetch) {
11315
- this.baseUrl = baseUrl;
11322
+ var API_HEADERS = { "content-type": "application/json", accept: "application/json" };
11323
+ var BIND_STATUS = { NONE: 0, PENDING: 1, COMPLETED: 2, EXPIRED: 3 };
11324
+ var QqQrProvider = class {
11325
+ constructor(portalHost = process.env.DSH_LARK_QQ_PORTAL_HOST ?? "q.qq.com", fetchImpl = fetch, genKey = () => randomBytes2(32).toString("base64")) {
11326
+ this.portalHost = portalHost;
11316
11327
  this.fetchImpl = fetchImpl;
11328
+ this.genKey = genKey;
11317
11329
  }
11318
- baseUrl;
11330
+ portalHost;
11319
11331
  fetchImpl;
11320
- type = "wechat";
11332
+ genKey;
11333
+ type = "qq";
11334
+ sessions = /* @__PURE__ */ new Map();
11321
11335
  async begin(_options) {
11322
- const response = await this.fetchImpl(`${this.baseUrl}/ilink/bot/get_bot_qrcode`, { method: "POST" });
11336
+ const aesKey = this.genKey();
11337
+ const response = await this.fetchImpl(`https://${this.portalHost}/lite/create_bind_task`, {
11338
+ method: "POST",
11339
+ headers: API_HEADERS,
11340
+ body: JSON.stringify({ key: aesKey })
11341
+ });
11323
11342
  const payload = await response.json().catch(() => ({}));
11324
- const qrUrl = payload.qrcode ?? payload.url ?? "";
11325
- if (!response.ok || !qrUrl) {
11326
- throw new Error(payload.msg ?? `wechat get_bot_qrcode failed: http ${response.status}`);
11343
+ const taskId = payload.data?.task_id;
11344
+ if (!response.ok || !taskId || payload.retcode !== void 0 && payload.retcode !== 0) {
11345
+ throw new Error(`qq create_bind_task failed: ${payload.msg ?? ""} (http ${response.status})`);
11327
11346
  }
11328
- return { providerType: this.type, sessionId: qrUrl, qrUrl, expireIn: 180 };
11347
+ const sessionId = randomUUID8();
11348
+ this.sessions.set(sessionId, { taskId, aesKey });
11349
+ const qrUrl = `https://q.qq.com/qqbot/openclaw/connect.html?task_id=${encodeURIComponent(taskId)}&_wv=2&source=dsh-lark-bot`;
11350
+ return { providerType: this.type, sessionId, qrUrl, expireIn: 600 };
11329
11351
  }
11330
11352
  async poll(sessionId, _signal) {
11331
- const response = await this.fetchImpl(`${this.baseUrl}/ilink/bot/getupdates`, {
11332
- method: "POST",
11333
- headers: { "content-type": "application/json" },
11334
- body: JSON.stringify({ qrcode: sessionId })
11335
- }).catch(() => void 0);
11336
- void response;
11353
+ const state = this.sessions.get(sessionId);
11354
+ if (!state) return { phase: "failed", error: "unknown session" };
11355
+ let data = {};
11356
+ try {
11357
+ const response = await this.fetchImpl(`https://${this.portalHost}/lite/poll_bind_result`, {
11358
+ method: "POST",
11359
+ headers: API_HEADERS,
11360
+ body: JSON.stringify({ task_id: state.taskId })
11361
+ });
11362
+ const payload = await response.json();
11363
+ if (!response.ok || payload.retcode !== void 0 && payload.retcode !== 0) return { phase: "pending" };
11364
+ data = payload.data ?? {};
11365
+ } catch {
11366
+ return { phase: "pending" };
11367
+ }
11368
+ const status = data.status ?? BIND_STATUS.NONE;
11369
+ if (status === BIND_STATUS.COMPLETED && data.bot_appid && data.bot_encrypt_secret) {
11370
+ let clientSecret;
11371
+ try {
11372
+ clientSecret = decryptSecret(data.bot_encrypt_secret, state.aesKey);
11373
+ } catch (error) {
11374
+ this.sessions.delete(sessionId);
11375
+ return { phase: "failed", error: `decrypt failed: ${error instanceof Error ? error.message : String(error)}` };
11376
+ }
11377
+ const target = data.user_openid ? `user:${data.user_openid}` : "";
11378
+ this.sessions.delete(sessionId);
11379
+ return {
11380
+ phase: "completed",
11381
+ channel: {
11382
+ id: "",
11383
+ type: "qq",
11384
+ label: "QQ",
11385
+ destination: target,
11386
+ secret: `${data.bot_appid}:${clientSecret}`
11387
+ }
11388
+ };
11389
+ }
11390
+ if (status === BIND_STATUS.EXPIRED) {
11391
+ this.sessions.delete(sessionId);
11392
+ return { phase: "expired" };
11393
+ }
11337
11394
  return { phase: "pending" };
11338
11395
  }
11339
11396
  };
11340
- var QqQrProvider = class {
11341
- constructor(portalHost = process.env.DSH_LARK_QQ_PORTAL_HOST ?? "api.sgroup.qq.com", fetchImpl = fetch) {
11342
- this.portalHost = portalHost;
11397
+ var WeChatQrProvider = class {
11398
+ constructor(baseUrl = process.env.DSH_LARK_WECHAT_ILINK_URL ?? "https://ilinkai.weixin.qq.com", fetchImpl = fetch) {
11399
+ this.baseUrl = baseUrl;
11343
11400
  this.fetchImpl = fetchImpl;
11344
11401
  }
11345
- portalHost;
11402
+ baseUrl;
11346
11403
  fetchImpl;
11347
- type = "qq";
11404
+ type = "wechat";
11405
+ sessions = /* @__PURE__ */ new Map();
11348
11406
  async begin(_options) {
11349
- const response = await this.fetchImpl(`https://${this.portalHost}/app/create_bind_task`, {
11350
- method: "POST",
11351
- headers: { "content-type": "application/json" },
11352
- body: JSON.stringify({})
11407
+ const response = await this.fetchImpl(`${this.baseUrl}/ilink/bot/get_bot_qrcode?bot_type=3`, {
11408
+ method: "GET"
11353
11409
  });
11354
11410
  const payload = await response.json().catch(() => ({}));
11355
- const taskId = payload.data?.task_id;
11356
- if (!response.ok || !taskId || payload.retcode !== void 0 && payload.retcode !== 0) {
11357
- throw new Error(`qq create_bind_task failed: http ${response.status}`);
11411
+ const qrcode2 = payload.qrcode ?? payload.url ?? "";
11412
+ if (!response.ok || !qrcode2) {
11413
+ throw new Error(payload.msg ?? `wechat get_bot_qrcode failed: http ${response.status}`);
11358
11414
  }
11359
- const qrUrl = `https://q.qq.com/bot/#/bind-task?key=${encodeURIComponent(taskId)}`;
11360
- return { providerType: this.type, sessionId: taskId, qrUrl, expireIn: 180 };
11415
+ const sessionId = randomUUID8();
11416
+ this.sessions.set(sessionId, { qrcode: qrcode2 });
11417
+ return { providerType: this.type, sessionId, qrUrl: qrcode2, expireIn: 180 };
11361
11418
  }
11362
11419
  async poll(sessionId, _signal) {
11363
- const response = await this.fetchImpl(`https://${this.portalHost}/app/poll_bind_result`, {
11364
- method: "POST",
11365
- headers: { "content-type": "application/json" },
11366
- body: JSON.stringify({ task_id: sessionId })
11367
- }).catch(() => void 0);
11368
- void response;
11369
- return { phase: "pending" };
11420
+ const state = this.sessions.get(sessionId);
11421
+ if (!state) return { phase: "failed", error: "unknown session" };
11422
+ const statusUrl = `${this.baseUrl}/ilink/bot/get_qrcode_status?qrcode=${encodeURIComponent(state.qrcode)}`;
11423
+ try {
11424
+ const response = await this.fetchImpl(statusUrl, {
11425
+ method: "GET",
11426
+ headers: { "iLink-App-Id": "bot", "iLink-App-ClientVersion": "131072" }
11427
+ });
11428
+ const payload = await response.json().catch(() => ({}));
11429
+ const status = String(payload.status ?? "wait").toLowerCase();
11430
+ if (status === "confirmed" || status === "success" || status === "scanned" || status === "2") {
11431
+ const token = payload.token ?? payload.access_token ?? "";
11432
+ const userId = payload.openid ?? payload.user_id ?? payload.to_user_id ?? "";
11433
+ this.sessions.delete(sessionId);
11434
+ return {
11435
+ phase: "completed",
11436
+ channel: { id: "", type: "wechat", label: "\u5FAE\u4FE1", destination: userId ? `${userId}|` : "", secret: token }
11437
+ };
11438
+ }
11439
+ if (status === "expired") {
11440
+ this.sessions.delete(sessionId);
11441
+ return { phase: "expired" };
11442
+ }
11443
+ return { phase: "pending" };
11444
+ } catch {
11445
+ return { phase: "pending" };
11446
+ }
11370
11447
  }
11371
11448
  };
11372
11449
  function buildSinkQrProviders() {
@@ -11378,7 +11455,21 @@ function coerceSinkQrChannel(input) {
11378
11455
  }
11379
11456
  function normalizeWechatDestination(value) {
11380
11457
  if (value.includes("|")) return value;
11381
- return splitDestination(value)[0] ? `${value}|` : value;
11458
+ const [id] = splitDestination(value);
11459
+ return id ? `${id}|` : value;
11460
+ }
11461
+ function decryptSecret(encryptedBase64, keyBase64) {
11462
+ const key = Buffer.from(keyBase64, "base64");
11463
+ const raw = Buffer.from(encryptedBase64, "base64");
11464
+ if (key.length !== 32) throw new Error("bind key must be 32 bytes");
11465
+ if (raw.length < 12 + 16) throw new Error("ciphertext too short");
11466
+ const iv = raw.subarray(0, 12);
11467
+ const body3 = raw.subarray(12);
11468
+ const tag = body3.subarray(body3.length - 16);
11469
+ const ciphertext = body3.subarray(0, body3.length - 16);
11470
+ const decipher = createDecipheriv("aes-256-gcm", key, iv);
11471
+ decipher.setAuthTag(tag);
11472
+ return Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
11382
11473
  }
11383
11474
 
11384
11475
  // src/onboard/qr-image.ts
@@ -13628,7 +13719,7 @@ function safe(value, maxBytes) {
13628
13719
  }
13629
13720
 
13630
13721
  // src/session/projection-protocol.ts
13631
- import { randomUUID as randomUUID8 } from "crypto";
13722
+ import { randomUUID as randomUUID9 } from "crypto";
13632
13723
  var WebSessionProjectionSource = class {
13633
13724
  constructor(transport) {
13634
13725
  this.transport = transport;
@@ -13667,7 +13758,7 @@ var WebSessionProjectionSource = class {
13667
13758
  });
13668
13759
  return { events, hasMore: value.hasMore === true };
13669
13760
  }
13670
- async prompt(sessionId, text, rpcId = randomUUID8()) {
13761
+ async prompt(sessionId, text, rpcId = randomUUID9()) {
13671
13762
  responseValue(await this.transport.rpc("session.prompt", {
13672
13763
  sessionId,
13673
13764
  mode: "queue",
@@ -14340,7 +14431,7 @@ function wait(ms) {
14340
14431
  }
14341
14432
 
14342
14433
  // src/commands/session-projection.ts
14343
- import { randomUUID as randomUUID9 } from "crypto";
14434
+ import { randomUUID as randomUUID10 } from "crypto";
14344
14435
  var SessionProjectionController = class {
14345
14436
  constructor(deps) {
14346
14437
  this.deps = deps;
@@ -14480,7 +14571,7 @@ workspace: \`${workspaceCwd}\``
14480
14571
  if (owner && owner.scope !== input.identity.scope && !this.deps.access.isAdmin(input.identity.actorId)) {
14481
14572
  throw new Error("\u8BE5 session \u5DF2\u7ED1\u5B9A\u5176\u4ED6\u98DE\u4E66 scope\uFF1B\u72EC\u5360\u8FC1\u79FB\u4EC5 profile \u7BA1\u7406\u5458\u53EF\u786E\u8BA4");
14482
14573
  }
14483
- const nonce = randomUUID9();
14574
+ const nonce = randomUUID10();
14484
14575
  const expiresAt = Date.now() + (this.deps.confirmationTtlMs ?? 10 * 6e4);
14485
14576
  const timer = setTimeout(() => this.pending.delete(nonce), expiresAt - Date.now());
14486
14577
  timer.unref?.();
@@ -15517,7 +15608,7 @@ function attachRunCardAnchors(channel, anchors) {
15517
15608
 
15518
15609
  // src/notify/server.ts
15519
15610
  import { createServer } from "http";
15520
- import { randomBytes as randomBytes2 } from "crypto";
15611
+ import { randomBytes as randomBytes3 } from "crypto";
15521
15612
  var NotifyServer = class {
15522
15613
  server;
15523
15614
  token;
@@ -15804,7 +15895,7 @@ function readBody(req) {
15804
15895
  });
15805
15896
  }
15806
15897
  function generateNotifyToken() {
15807
- return `dsh-lark-${randomBytes2(18).toString("hex")}`;
15898
+ return `dsh-lark-${randomBytes3(18).toString("hex")}`;
15808
15899
  }
15809
15900
 
15810
15901
  // src/notify/ask-handler.ts
@@ -15996,7 +16087,7 @@ async function settleCancelledCard(deps, chatId, cardMessageId, options) {
15996
16087
  }
15997
16088
 
15998
16089
  // src/notify/approval-handler.ts
15999
- import { randomUUID as randomUUID10 } from "crypto";
16090
+ import { randomUUID as randomUUID11 } from "crypto";
16000
16091
  init_tool_policy();
16001
16092
  function buildApprovalHandler(deps) {
16002
16093
  return async (payload, signal) => {
@@ -16039,7 +16130,7 @@ ${policyDenialText(denial)}
16039
16130
  return { ok: true, outcome: "rejected", denial };
16040
16131
  }
16041
16132
  if (payload.lowRisk) return { ok: true, outcome: "allowed-once" };
16042
- const id = `approval-${randomUUID10().replaceAll("-", "")}`;
16133
+ const id = `approval-${randomUUID11().replaceAll("-", "")}`;
16043
16134
  const request = {
16044
16135
  id,
16045
16136
  ...payload.callId === void 0 ? {} : { callId: payload.callId },
@@ -16368,14 +16459,16 @@ var QqSink = class {
16368
16459
  type = "qq";
16369
16460
  async send(channel, message) {
16370
16461
  const [appId, clientSecret] = splitAppCredential(channel.secret);
16371
- const groupOpenId = channel.destination;
16372
- if (!appId || !clientSecret || !groupOpenId) {
16462
+ const target = channel.destination;
16463
+ if (!appId || !clientSecret || !target) {
16373
16464
  log.warn("sink:qq", "missing-credential", { channel: channel.id });
16374
16465
  return false;
16375
16466
  }
16467
+ const isC2c = target.startsWith("user:");
16468
+ const openId = isC2c ? target.slice("user:".length) : target;
16469
+ const url = `${this.apiBase}/v2/${isC2c ? "users" : "groups"}/${encodeURIComponent(openId)}/messages`;
16376
16470
  try {
16377
16471
  const token = await this.fetchAccessToken(appId, clientSecret);
16378
- const url = `${this.apiBase}/v2/groups/${encodeURIComponent(groupOpenId)}/messages`;
16379
16472
  const controller = new AbortController();
16380
16473
  const timer = setTimeout(() => controller.abort(), 1e4);
16381
16474
  timer.unref?.();
@@ -16660,13 +16753,60 @@ async function onboardPersonalAgent(deps = {}) {
16660
16753
  // src/media/attachments.ts
16661
16754
  import { mkdir as mkdir16, readFile as readFile24, rename as rename3, rm as rm9, stat as stat9 } from "fs/promises";
16662
16755
  import { join as join23 } from "path";
16756
+
16757
+ // src/media/image-scale.ts
16758
+ import { writeFile as writeFile8 } from "fs/promises";
16759
+ function formatFromExtension(path) {
16760
+ const lower = path.toLowerCase();
16761
+ if (lower.endsWith(".png")) return "png";
16762
+ if (lower.endsWith(".jpg") || lower.endsWith(".jpeg")) return "jpeg";
16763
+ if (lower.endsWith(".webp")) return "webp";
16764
+ if (lower.endsWith(".gif")) return "gif";
16765
+ return void 0;
16766
+ }
16767
+ async function downscaleImageIfNeeded(path, maxDimension) {
16768
+ if (typeof maxDimension !== "number" || !Number.isFinite(maxDimension) || maxDimension <= 0) {
16769
+ return path;
16770
+ }
16771
+ const format = formatFromExtension(path);
16772
+ if (!format) return path;
16773
+ let sharp;
16774
+ try {
16775
+ const mod = await import("sharp");
16776
+ sharp = mod.default;
16777
+ } catch {
16778
+ return path;
16779
+ }
16780
+ if (!sharp) return path;
16781
+ try {
16782
+ const image = sharp(path, { failOn: "error" });
16783
+ const meta = await image.metadata();
16784
+ const width = meta.width ?? 0;
16785
+ const height = meta.height ?? 0;
16786
+ const longSide = Math.max(width, height);
16787
+ if (longSide <= maxDimension) return path;
16788
+ const data = await sharp(path, { failOn: "error" }).resize({
16789
+ width: maxDimension,
16790
+ height: maxDimension,
16791
+ fit: "inside",
16792
+ withoutEnlargement: true
16793
+ }).toFormat(format).toBuffer();
16794
+ await writeFile8(path, data);
16795
+ return path;
16796
+ } catch {
16797
+ return path;
16798
+ }
16799
+ }
16800
+
16801
+ // src/media/attachments.ts
16663
16802
  var MAX_TEXT_FILE_BYTES = 256e3;
16664
16803
  function assertSafeMediaName(mediaDir, destination) {
16665
16804
  if (!isPathWithin(mediaDir, destination)) {
16666
16805
  throw new Error(`unsafe attachment destination rejected: ${destination}`);
16667
16806
  }
16668
16807
  }
16669
- async function prepareAttachments(channel, message, mediaDir) {
16808
+ async function prepareAttachments(channel, message, mediaDir, options = {}) {
16809
+ const { maxImageDimension = 0 } = options;
16670
16810
  await mkdir16(mediaDir, { recursive: true });
16671
16811
  const result = { imagePaths: [], textFileNotes: [] };
16672
16812
  for (const resource of message.resources) {
@@ -16687,7 +16827,8 @@ async function prepareAttachments(channel, message, mediaDir) {
16687
16827
  const imagePath = `${destination}${detected.extension}`;
16688
16828
  assertSafeMediaName(mediaDir, imagePath);
16689
16829
  await rename3(downloadPath, imagePath);
16690
- result.imagePaths.push(imagePath);
16830
+ const finalPath = await downscaleImageIfNeeded(imagePath, maxImageDimension);
16831
+ result.imagePaths.push(finalPath);
16691
16832
  } catch (error) {
16692
16833
  await rm9(downloadPath, { force: true });
16693
16834
  throw error;
@@ -17045,7 +17186,7 @@ function normalizeContextSnapshot(value) {
17045
17186
 
17046
17187
  // src/session/projection-store.ts
17047
17188
  import { readFile as readFile26 } from "fs/promises";
17048
- import { randomUUID as randomUUID11 } from "crypto";
17189
+ import { randomUUID as randomUUID12 } from "crypto";
17049
17190
  var MAX_RECENT_MESSAGES = 64;
17050
17191
  var MAX_PROMPT_CORRELATIONS = 64;
17051
17192
  var PROMPT_CORRELATION_TTL_MS = 24 * 60 * 6e4;
@@ -17112,7 +17253,7 @@ var SessionProjectionStore = class {
17112
17253
  recentMessages: currentOwner?.scope === input.scope && currentOwner.workspaceCwd === input.workspaceCwd ? structuredClone(currentOwner.recentMessages) : [],
17113
17254
  promptCorrelations: structuredClone(currentOwner?.promptCorrelations ?? []),
17114
17255
  boundAt: (/* @__PURE__ */ new Date()).toISOString(),
17115
- generationId: randomUUID11()
17256
+ generationId: randomUUID12()
17116
17257
  };
17117
17258
  this.data.bindings[targetKey] = binding;
17118
17259
  return {
@@ -17269,8 +17410,8 @@ function normalizeCorrelation(value) {
17269
17410
 
17270
17411
  // src/session/archive.ts
17271
17412
  import { execFile as execFile2 } from "child_process";
17272
- import { randomBytes as randomBytes3 } from "crypto";
17273
- import { access, mkdir as mkdir17, readdir as readdir3, readFile as readFile27, unlink, writeFile as writeFile8 } from "fs/promises";
17413
+ import { randomBytes as randomBytes4 } from "crypto";
17414
+ import { access, mkdir as mkdir17, readdir as readdir3, readFile as readFile27, unlink, writeFile as writeFile9 } from "fs/promises";
17274
17415
  import { join as join24 } from "path";
17275
17416
  import { promisify } from "util";
17276
17417
  var execFileAsync = promisify(execFile2);
@@ -17280,7 +17421,7 @@ function archiveScopeSlug(scope) {
17280
17421
  }
17281
17422
  function timestampId() {
17282
17423
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:]/g, "").replace(/\.\d{3}/, "");
17283
- return `${stamp}-${randomBytes3(3).toString("hex")}`;
17424
+ return `${stamp}-${randomBytes4(3).toString("hex")}`;
17284
17425
  }
17285
17426
  function renderMarkdown(input, record) {
17286
17427
  const lines = [
@@ -17353,8 +17494,8 @@ var SessionArchive = class {
17353
17494
  const markdownPath = join24(scopeDir, `${id}.md`);
17354
17495
  await mkdir17(scopeDir, { recursive: true });
17355
17496
  await Promise.all([
17356
- writeFile8(jsonlPath, renderJsonl(input, { archiveId: id, archivedAt, source }), "utf8"),
17357
- writeFile8(
17497
+ writeFile9(jsonlPath, renderJsonl(input, { archiveId: id, archivedAt, source }), "utf8"),
17498
+ writeFile9(
17358
17499
  markdownPath,
17359
17500
  renderMarkdown(input, { archiveId: id, archivedAt, source }),
17360
17501
  "utf8"
@@ -17594,7 +17735,7 @@ async function safeRemove(path) {
17594
17735
 
17595
17736
  // src/workspace/git-worktree.ts
17596
17737
  import { execFile as execFile3 } from "child_process";
17597
- import { createHash as createHash2, randomBytes as randomBytes4 } from "crypto";
17738
+ import { createHash as createHash2, randomBytes as randomBytes5 } from "crypto";
17598
17739
  import { access as access2, copyFile, mkdir as mkdir18, realpath as realpath2 } from "fs/promises";
17599
17740
  import { dirname as dirname16, join as join25 } from "path";
17600
17741
  import { promisify as promisify2 } from "util";
@@ -17655,7 +17796,7 @@ var GitWorktreeManager = class {
17655
17796
  return { cwd: target, created: false };
17656
17797
  }
17657
17798
  }
17658
- const branch = `dsh-lark/${slug}-${Date.now().toString(36)}-${randomBytes4(3).toString("hex")}`;
17799
+ const branch = `dsh-lark/${slug}-${Date.now().toString(36)}-${randomBytes5(3).toString("hex")}`;
17659
17800
  await mkdir18(this.options.worktreesRoot, { recursive: true });
17660
17801
  await this.runGit(["worktree", "add", "-b", branch, target, "HEAD"], base);
17661
17802
  await this.ensureProjectRules(base, target);
@@ -18639,7 +18780,7 @@ function projectDiagnosticLogs(lines) {
18639
18780
  }
18640
18781
 
18641
18782
  // src/secret/registry.ts
18642
- import { randomUUID as randomUUID12 } from "crypto";
18783
+ import { randomUUID as randomUUID13 } from "crypto";
18643
18784
  var SecretRequestRegistry = class {
18644
18785
  constructor(writer, options = {}) {
18645
18786
  this.writer = writer;
@@ -18652,7 +18793,7 @@ var SecretRequestRegistry = class {
18652
18793
  now;
18653
18794
  register(input) {
18654
18795
  this.writer.validate(input.target, input.reference);
18655
- const id = `secret-${randomUUID12().replaceAll("-", "")}`;
18796
+ const id = `secret-${randomUUID13().replaceAll("-", "")}`;
18656
18797
  let resolve6;
18657
18798
  const promise = new Promise((settle) => {
18658
18799
  resolve6 = settle;
@@ -18802,7 +18943,7 @@ function buildSecretHandler(deps) {
18802
18943
  init_own_package();
18803
18944
 
18804
18945
  // src/guardian/update-handoff.ts
18805
- import { createHash as createHash3, randomUUID as randomUUID13 } from "crypto";
18946
+ import { createHash as createHash3, randomUUID as randomUUID14 } from "crypto";
18806
18947
  import { spawn as spawn7 } from "child_process";
18807
18948
  import { chmod, mkdir as mkdir21, readFile as readFile32, rm as rm10 } from "fs/promises";
18808
18949
  import { dirname as dirname19, join as join26 } from "path";
@@ -18976,7 +19117,7 @@ var GuardianUpdateHandoff = class {
18976
19117
  this.options = options;
18977
19118
  this.launch = options.launch ?? defaultLaunch;
18978
19119
  this.now = options.now ?? (() => /* @__PURE__ */ new Date());
18979
- this.id = options.id ?? randomUUID13;
19120
+ this.id = options.id ?? randomUUID14;
18980
19121
  }
18981
19122
  options;
18982
19123
  launch;
@@ -19092,14 +19233,14 @@ var GuardianUpdateHandoff = class {
19092
19233
  };
19093
19234
 
19094
19235
  // src/upgrade/channel-update.ts
19095
- import { randomUUID as randomUUID14 } from "crypto";
19236
+ import { randomUUID as randomUUID15 } from "crypto";
19096
19237
  var OFFER_TTL_MS = 10 * 6e4;
19097
19238
  var ChannelUpdateController = class {
19098
19239
  constructor(options) {
19099
19240
  this.options = options;
19100
19241
  this.current = options.current ?? currentVersion();
19101
19242
  this.probe = options.probe ?? (() => latestVersion({ cacheMs: 0 }));
19102
- this.id = options.id ?? randomUUID14;
19243
+ this.id = options.id ?? randomUUID15;
19103
19244
  this.now = options.now ?? Date.now;
19104
19245
  this.ttl = options.offerTtlMs ?? OFFER_TTL_MS;
19105
19246
  }
@@ -19458,7 +19599,7 @@ async function startBridgeEngine(options) {
19458
19599
  ledgerClaimed = await claimJobDispatch({
19459
19600
  jobs,
19460
19601
  messageIds: ledgerMessageIds,
19461
- runId: `dispatch-${randomUUID15()}`,
19602
+ runId: `dispatch-${randomUUID16()}`,
19462
19603
  first,
19463
19604
  channel: streaming
19464
19605
  });
@@ -19468,7 +19609,8 @@ async function startBridgeEngine(options) {
19468
19609
  attachments: await prepareAttachments(
19469
19610
  larkChannel,
19470
19611
  message,
19471
- paths.mediaDir(profileName)
19612
+ paths.mediaDir(profileName),
19613
+ { maxImageDimension: env.imageMaxDimension }
19472
19614
  )
19473
19615
  })));
19474
19616
  const messages = prepared.flatMap(({ message, attachments }) => [
@@ -19917,7 +20059,7 @@ function waitForShutdown() {
19917
20059
  init_dsh_runtime();
19918
20060
  init_own_package();
19919
20061
  import { spawn as spawn8 } from "child_process";
19920
- import { mkdir as mkdir23, readFile as readFile33, writeFile as writeFile9 } from "fs/promises";
20062
+ import { mkdir as mkdir23, readFile as readFile33, writeFile as writeFile10 } from "fs/promises";
19921
20063
  import { homedir as homedir17 } from "os";
19922
20064
  import { join as join28 } from "path";
19923
20065
  import { parse } from "yaml";
@@ -20017,7 +20159,7 @@ allowBuilds:
20017
20159
  existing = existing.replace(/(allowBuilds:\s*\n)/, `$1 ${allowBuilds}
20018
20160
  `);
20019
20161
  }
20020
- await writeFile9(workspaceFile, existing, "utf8");
20162
+ await writeFile10(workspaceFile, existing, "utf8");
20021
20163
  }
20022
20164
  async function preserveInstalledPnpmVersion(profileDir) {
20023
20165
  const packageFile = join28(profileDir, "package.json");
@@ -20040,7 +20182,7 @@ async function preserveInstalledPnpmVersion(profileDir) {
20040
20182
  return;
20041
20183
  }
20042
20184
  profilePackage.packageManager = packageManager;
20043
- await writeFile9(packageFile, `${JSON.stringify(profilePackage, null, 2)}
20185
+ await writeFile10(packageFile, `${JSON.stringify(profilePackage, null, 2)}
20044
20186
  `, "utf8");
20045
20187
  } catch {
20046
20188
  }
@@ -20573,7 +20715,7 @@ ${changeLines.join("\n")}
20573
20715
  import { join as join33 } from "path";
20574
20716
 
20575
20717
  // src/guardian/service.ts
20576
- import { randomUUID as randomUUID16 } from "crypto";
20718
+ import { randomUUID as randomUUID17 } from "crypto";
20577
20719
  import { readFileSync as readFileSync6 } from "fs";
20578
20720
  import { homedir as homedir21 } from "os";
20579
20721
  import { join as join32 } from "path";
@@ -20646,7 +20788,7 @@ init_process();
20646
20788
 
20647
20789
  // src/guardian/safe-profile.ts
20648
20790
  init_dsh_runtime();
20649
- import { mkdir as mkdir26, writeFile as writeFile10 } from "fs/promises";
20791
+ import { mkdir as mkdir26, writeFile as writeFile11 } from "fs/promises";
20650
20792
  import { existsSync as existsSync8 } from "fs";
20651
20793
  import { join as join31 } from "path";
20652
20794
  var SAFE_CORE_BUNDLES = [
@@ -20666,7 +20808,7 @@ async function ensureSafeProfile(options) {
20666
20808
  let created = false;
20667
20809
  const manifest = join31(root, "package.json");
20668
20810
  if (!existsSync8(manifest)) {
20669
- await writeFile10(
20811
+ await writeFile11(
20670
20812
  manifest,
20671
20813
  `${JSON.stringify(
20672
20814
  {
@@ -20689,7 +20831,7 @@ async function ensureSafeProfile(options) {
20689
20831
  }
20690
20832
  const rootConfig = join31(root, "cordis.yml");
20691
20833
  if (!existsSync8(rootConfig)) {
20692
- await writeFile10(
20834
+ await writeFile11(
20693
20835
  rootConfig,
20694
20836
  "# dsh profile root - an empty entry list; the tree is composed as patches.\n[]\n",
20695
20837
  "utf8"
@@ -20698,12 +20840,12 @@ async function ensureSafeProfile(options) {
20698
20840
  }
20699
20841
  const userPatch = join31(root, "cordis.patch.yml");
20700
20842
  if (!existsSync8(userPatch)) {
20701
- await writeFile10(userPatch, "[]\n", "utf8");
20843
+ await writeFile11(userPatch, "[]\n", "utf8");
20702
20844
  created = true;
20703
20845
  }
20704
20846
  const workspace = join31(root, "pnpm-workspace.yaml");
20705
20847
  if (!existsSync8(workspace)) {
20706
- await writeFile10(
20848
+ await writeFile11(
20707
20849
  workspace,
20708
20850
  [
20709
20851
  "packages:",
@@ -21420,7 +21562,7 @@ var GuardianService = class {
21420
21562
  }
21421
21563
  const transcript = this.transcripts.get(scope) ?? [];
21422
21564
  const prompt = buildSafePrompt(transcript, msg.content);
21423
- const runId = randomUUID16();
21565
+ const runId = randomUUID17();
21424
21566
  const density = this.options.safeDensity;
21425
21567
  const timeoutMs = this.options.safeTimeoutMs;
21426
21568
  const now = Date.now();