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 +1 -1
- package/README_EN.md +1 -1
- package/dist/cli.js +222 -80
- package/dist/cli.js.map +1 -1
- package/dist/plugin.d.ts +2 -0
- package/dist/plugin.js +220 -78
- package/dist/plugin.js.map +1 -1
- package/package.json +6 -2
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-
|
|
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-
|
|
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-
|
|
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
|
|
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
|
|
11314
|
-
|
|
11315
|
-
|
|
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
|
-
|
|
11330
|
+
portalHost;
|
|
11319
11331
|
fetchImpl;
|
|
11320
|
-
|
|
11332
|
+
genKey;
|
|
11333
|
+
type = "qq";
|
|
11334
|
+
sessions = /* @__PURE__ */ new Map();
|
|
11321
11335
|
async begin(_options) {
|
|
11322
|
-
const
|
|
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
|
|
11325
|
-
if (!response.ok || !
|
|
11326
|
-
throw new Error(payload.msg ??
|
|
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
|
-
|
|
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
|
|
11332
|
-
|
|
11333
|
-
|
|
11334
|
-
|
|
11335
|
-
|
|
11336
|
-
|
|
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
|
|
11341
|
-
constructor(
|
|
11342
|
-
this.
|
|
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
|
-
|
|
11402
|
+
baseUrl;
|
|
11346
11403
|
fetchImpl;
|
|
11347
|
-
type = "
|
|
11404
|
+
type = "wechat";
|
|
11405
|
+
sessions = /* @__PURE__ */ new Map();
|
|
11348
11406
|
async begin(_options) {
|
|
11349
|
-
const response = await this.fetchImpl(
|
|
11350
|
-
method: "
|
|
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
|
|
11356
|
-
if (!response.ok || !
|
|
11357
|
-
throw new Error(`
|
|
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
|
|
11360
|
-
|
|
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
|
|
11364
|
-
|
|
11365
|
-
|
|
11366
|
-
|
|
11367
|
-
|
|
11368
|
-
|
|
11369
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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-${
|
|
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
|
|
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-${
|
|
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
|
|
16372
|
-
if (!appId || !clientSecret || !
|
|
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
|
-
|
|
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
|
|
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:
|
|
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
|
|
17273
|
-
import { access, mkdir as mkdir17, readdir as readdir3, readFile as readFile27, unlink, writeFile as
|
|
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}-${
|
|
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
|
-
|
|
17357
|
-
|
|
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
|
|
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)}-${
|
|
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
|
|
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-${
|
|
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
|
|
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 ??
|
|
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
|
|
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 ??
|
|
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-${
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
21565
|
+
const runId = randomUUID17();
|
|
21424
21566
|
const density = this.options.safeDensity;
|
|
21425
21567
|
const timeoutMs = this.options.safeTimeoutMs;
|
|
21426
21568
|
const now = Date.now();
|