dsh-remote-control 2.0.0 → 2.0.1
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/bundle/client.cjs +19 -7
- package/dist/bundle/index.js +221 -91
- package/package.json +2 -2
package/dist/bundle/client.cjs
CHANGED
|
@@ -75,12 +75,17 @@ function pillLabel(status) {
|
|
|
75
75
|
if (waiting > 0) return { text: `\u7B49 ${waiting} \u4EF6\u4E8B`, tone: "wait" };
|
|
76
76
|
return { text: "\u5DF2\u914D\u5BF9", tone: "on" };
|
|
77
77
|
}
|
|
78
|
+
if (pairingCount(status) > 0) return { text: "\u624B\u673A\u79BB\u7EBF", tone: "wait" };
|
|
78
79
|
return { text: "\u672A\u914D\u5BF9", tone: "off" };
|
|
79
80
|
}
|
|
80
81
|
function waitingCount(status) {
|
|
81
82
|
const count = status?.waiting;
|
|
82
83
|
return typeof count === "number" && count > 0 ? Math.min(Math.floor(count), 99) : 0;
|
|
83
84
|
}
|
|
85
|
+
function pairingCount(status) {
|
|
86
|
+
const count = status?.pairings;
|
|
87
|
+
return typeof count === "number" ? count : 0;
|
|
88
|
+
}
|
|
84
89
|
function humanDuration(sec) {
|
|
85
90
|
const total = typeof sec === "number" && sec > 0 ? Math.floor(sec) : 0;
|
|
86
91
|
if (total < 60) return `${total} \u79D2`;
|
|
@@ -236,7 +241,7 @@ function buildPill(root, deps) {
|
|
|
236
241
|
let expiresInMs = 0;
|
|
237
242
|
let lastStatus;
|
|
238
243
|
let disposed = false;
|
|
239
|
-
const
|
|
244
|
+
const pairingNow = () => pairingCount(lastStatus);
|
|
240
245
|
const write = () => {
|
|
241
246
|
const next = pillLabel(lastStatus);
|
|
242
247
|
label.textContent = next.text;
|
|
@@ -268,11 +273,16 @@ function buildPill(root, deps) {
|
|
|
268
273
|
head.appendChild(stateText);
|
|
269
274
|
const actions = doc.createElement("div");
|
|
270
275
|
actions.className = "drc-actions";
|
|
271
|
-
const action =
|
|
276
|
+
const action = pairingNow() > 0 ? { label: "\u9000\u51FA\u914D\u5BF9", run: requestUnpair } : { label: "\u5237\u65B0", run: requestPairing };
|
|
272
277
|
actions.appendChild(buttonOf(action.label, () => void action.run()));
|
|
273
278
|
head.appendChild(actions);
|
|
274
279
|
return head;
|
|
275
280
|
};
|
|
281
|
+
const offlineNote = () => {
|
|
282
|
+
if (!lastStatus) return null;
|
|
283
|
+
if (pillLabel(lastStatus).text !== "\u624B\u673A\u79BB\u7EBF") return null;
|
|
284
|
+
return text("p", "drc-note", "\u914D\u5BF9\u8FD8\u5728\uFF1A\u5C0F\u7A0B\u5E8F\u56DE\u524D\u53F0\u4F1A\u81EA\u52A8\u91CD\u8FDE\uFF0C\u4E0D\u7528\u91CD\u65B0\u626B\u7801\u3002");
|
|
285
|
+
};
|
|
276
286
|
const infoRows = () => {
|
|
277
287
|
if (!lastStatus) return [];
|
|
278
288
|
const rows = [
|
|
@@ -305,14 +315,16 @@ function buildPill(root, deps) {
|
|
|
305
315
|
panel.appendChild(text("p", "drc-code", view.token));
|
|
306
316
|
panel.appendChild(text("p", "drc-note", qrNote()));
|
|
307
317
|
} else if (view.kind === "unavailable" || view.kind === "failed") {
|
|
308
|
-
const
|
|
318
|
+
const note2 = view.kind === "unavailable" ? text("p", "drc-note", view.reason) : (() => {
|
|
309
319
|
const node = text("p", "drc-note", `\u914D\u5BF9\u8BF7\u6C42\u6CA1\u6210\u529F\uFF1A${view.detail}`);
|
|
310
320
|
node.setAttribute("data-kind", "failed");
|
|
311
321
|
return node;
|
|
312
322
|
})();
|
|
313
|
-
panel.appendChild(
|
|
323
|
+
panel.appendChild(note2);
|
|
314
324
|
}
|
|
315
325
|
for (const row of infoRows()) panel.appendChild(row);
|
|
326
|
+
const note = offlineNote();
|
|
327
|
+
if (note) panel.appendChild(note);
|
|
316
328
|
};
|
|
317
329
|
const closePanel = () => {
|
|
318
330
|
if (countTimer !== void 0) {
|
|
@@ -373,7 +385,7 @@ function buildPill(root, deps) {
|
|
|
373
385
|
warn("\u9000\u51FA\u914D\u5BF9\u8BF7\u6C42\u5931\u8D25\uFF08\u9762\u677F\u4F1A\u9760\u4E0B\u4E00\u6B21\u8F6E\u8BE2\u5BF9\u8D26\uFF09", error);
|
|
374
386
|
}
|
|
375
387
|
if (disposed || !panel) return;
|
|
376
|
-
if (lastStatus) lastStatus = { ...lastStatus, paired: 0 };
|
|
388
|
+
if (lastStatus) lastStatus = { ...lastStatus, paired: 0, pairings: 0 };
|
|
377
389
|
write();
|
|
378
390
|
view = { kind: "loading" };
|
|
379
391
|
paint();
|
|
@@ -388,7 +400,7 @@ function buildPill(root, deps) {
|
|
|
388
400
|
panel.tabIndex = -1;
|
|
389
401
|
root.appendChild(panel);
|
|
390
402
|
button.setAttribute("aria-expanded", "true");
|
|
391
|
-
if (
|
|
403
|
+
if (pairingNow() > 0) {
|
|
392
404
|
view = { kind: "info" };
|
|
393
405
|
paint();
|
|
394
406
|
} else {
|
|
@@ -430,7 +442,7 @@ function buildPill(root, deps) {
|
|
|
430
442
|
const body = await response.json?.();
|
|
431
443
|
if (!body || typeof body !== "object") return;
|
|
432
444
|
lastStatus = body;
|
|
433
|
-
if (view.kind === "qr" &&
|
|
445
|
+
if (view.kind === "qr" && pairingNow() > 0) {
|
|
434
446
|
view = { kind: "info" };
|
|
435
447
|
if (countTimer !== void 0) {
|
|
436
448
|
clearInterval(countTimer);
|
package/dist/bundle/index.js
CHANGED
|
@@ -7486,10 +7486,10 @@ var require_segments = __commonJS({
|
|
|
7486
7486
|
const segs = getSegmentsFromString(data, Utils.isKanjiModeEnabled());
|
|
7487
7487
|
const nodes = buildNodes(segs);
|
|
7488
7488
|
const graph = buildGraph(nodes, version2);
|
|
7489
|
-
const
|
|
7489
|
+
const path7 = dijkstra.find_path(graph.map, "start", "end");
|
|
7490
7490
|
const optimizedSegs = [];
|
|
7491
|
-
for (let i = 1; i <
|
|
7492
|
-
optimizedSegs.push(graph.table[
|
|
7491
|
+
for (let i = 1; i < path7.length - 1; i++) {
|
|
7492
|
+
optimizedSegs.push(graph.table[path7[i]].node);
|
|
7493
7493
|
}
|
|
7494
7494
|
return exports.fromArray(mergeSegments(optimizedSegs));
|
|
7495
7495
|
};
|
|
@@ -9925,7 +9925,7 @@ var require_utils2 = __commonJS({
|
|
|
9925
9925
|
// ../../node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/renderer/png.js
|
|
9926
9926
|
var require_png2 = __commonJS({
|
|
9927
9927
|
"../../node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/renderer/png.js"(exports) {
|
|
9928
|
-
var
|
|
9928
|
+
var fs2 = __require("fs");
|
|
9929
9929
|
var PNG = require_png().PNG;
|
|
9930
9930
|
var Utils = require_utils2();
|
|
9931
9931
|
exports.render = function render(qrData, options) {
|
|
@@ -9966,7 +9966,7 @@ var require_png2 = __commonJS({
|
|
|
9966
9966
|
});
|
|
9967
9967
|
png.pack();
|
|
9968
9968
|
};
|
|
9969
|
-
exports.renderToFile = function renderToFile(
|
|
9969
|
+
exports.renderToFile = function renderToFile(path7, qrData, options, cb) {
|
|
9970
9970
|
if (typeof cb === "undefined") {
|
|
9971
9971
|
cb = options;
|
|
9972
9972
|
options = void 0;
|
|
@@ -9977,7 +9977,7 @@ var require_png2 = __commonJS({
|
|
|
9977
9977
|
called = true;
|
|
9978
9978
|
cb.apply(null, args);
|
|
9979
9979
|
};
|
|
9980
|
-
const stream =
|
|
9980
|
+
const stream = fs2.createWriteStream(path7);
|
|
9981
9981
|
stream.on("error", done);
|
|
9982
9982
|
stream.on("close", done);
|
|
9983
9983
|
exports.renderToFileStream(stream, qrData, options);
|
|
@@ -10039,14 +10039,14 @@ var require_utf8 = __commonJS({
|
|
|
10039
10039
|
}
|
|
10040
10040
|
return output2;
|
|
10041
10041
|
};
|
|
10042
|
-
exports.renderToFile = function renderToFile(
|
|
10042
|
+
exports.renderToFile = function renderToFile(path7, qrData, options, cb) {
|
|
10043
10043
|
if (typeof cb === "undefined") {
|
|
10044
10044
|
cb = options;
|
|
10045
10045
|
options = void 0;
|
|
10046
10046
|
}
|
|
10047
|
-
const
|
|
10047
|
+
const fs2 = __require("fs");
|
|
10048
10048
|
const utf82 = exports.render(qrData, options);
|
|
10049
|
-
|
|
10049
|
+
fs2.writeFile(path7, utf82, cb);
|
|
10050
10050
|
};
|
|
10051
10051
|
}
|
|
10052
10052
|
});
|
|
@@ -10167,7 +10167,7 @@ var require_svg_tag = __commonJS({
|
|
|
10167
10167
|
return str;
|
|
10168
10168
|
}
|
|
10169
10169
|
function qrToPath(data, size, margin) {
|
|
10170
|
-
let
|
|
10170
|
+
let path7 = "";
|
|
10171
10171
|
let moveBy = 0;
|
|
10172
10172
|
let newRow = false;
|
|
10173
10173
|
let lineLength = 0;
|
|
@@ -10178,19 +10178,19 @@ var require_svg_tag = __commonJS({
|
|
|
10178
10178
|
if (data[i]) {
|
|
10179
10179
|
lineLength++;
|
|
10180
10180
|
if (!(i > 0 && col > 0 && data[i - 1])) {
|
|
10181
|
-
|
|
10181
|
+
path7 += newRow ? svgCmd("M", col + margin, 0.5 + row + margin) : svgCmd("m", moveBy, 0);
|
|
10182
10182
|
moveBy = 0;
|
|
10183
10183
|
newRow = false;
|
|
10184
10184
|
}
|
|
10185
10185
|
if (!(col + 1 < size && data[i + 1])) {
|
|
10186
|
-
|
|
10186
|
+
path7 += svgCmd("h", lineLength);
|
|
10187
10187
|
lineLength = 0;
|
|
10188
10188
|
}
|
|
10189
10189
|
} else {
|
|
10190
10190
|
moveBy++;
|
|
10191
10191
|
}
|
|
10192
10192
|
}
|
|
10193
|
-
return
|
|
10193
|
+
return path7;
|
|
10194
10194
|
}
|
|
10195
10195
|
exports.render = function render(qrData, options, cb) {
|
|
10196
10196
|
const opts = Utils.getOptions(options);
|
|
@@ -10198,10 +10198,10 @@ var require_svg_tag = __commonJS({
|
|
|
10198
10198
|
const data = qrData.modules.data;
|
|
10199
10199
|
const qrcodesize = size + opts.margin * 2;
|
|
10200
10200
|
const bg = !opts.color.light.a ? "" : "<path " + getColorAttrib(opts.color.light, "fill") + ' d="M0 0h' + qrcodesize + "v" + qrcodesize + 'H0z"/>';
|
|
10201
|
-
const
|
|
10201
|
+
const path7 = "<path " + getColorAttrib(opts.color.dark, "stroke") + ' d="' + qrToPath(data, size, opts.margin) + '"/>';
|
|
10202
10202
|
const viewBox = 'viewBox="0 0 ' + qrcodesize + " " + qrcodesize + '"';
|
|
10203
10203
|
const width = !opts.width ? "" : 'width="' + opts.width + '" height="' + opts.width + '" ';
|
|
10204
|
-
const svgTag = '<svg xmlns="http://www.w3.org/2000/svg" ' + width + viewBox + ' shape-rendering="crispEdges">' + bg +
|
|
10204
|
+
const svgTag = '<svg xmlns="http://www.w3.org/2000/svg" ' + width + viewBox + ' shape-rendering="crispEdges">' + bg + path7 + "</svg>\n";
|
|
10205
10205
|
if (typeof cb === "function") {
|
|
10206
10206
|
cb(null, svgTag);
|
|
10207
10207
|
}
|
|
@@ -10215,15 +10215,15 @@ var require_svg = __commonJS({
|
|
|
10215
10215
|
"../../node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/renderer/svg.js"(exports) {
|
|
10216
10216
|
var svgTagRenderer = require_svg_tag();
|
|
10217
10217
|
exports.render = svgTagRenderer.render;
|
|
10218
|
-
exports.renderToFile = function renderToFile(
|
|
10218
|
+
exports.renderToFile = function renderToFile(path7, qrData, options, cb) {
|
|
10219
10219
|
if (typeof cb === "undefined") {
|
|
10220
10220
|
cb = options;
|
|
10221
10221
|
options = void 0;
|
|
10222
10222
|
}
|
|
10223
|
-
const
|
|
10223
|
+
const fs2 = __require("fs");
|
|
10224
10224
|
const svgTag = exports.render(qrData, options);
|
|
10225
10225
|
const xmlStr = '<?xml version="1.0" encoding="utf-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">' + svgTag;
|
|
10226
|
-
|
|
10226
|
+
fs2.writeFile(path7, xmlStr, cb);
|
|
10227
10227
|
};
|
|
10228
10228
|
}
|
|
10229
10229
|
});
|
|
@@ -10381,8 +10381,8 @@ var require_server = __commonJS({
|
|
|
10381
10381
|
cb
|
|
10382
10382
|
};
|
|
10383
10383
|
}
|
|
10384
|
-
function getTypeFromFilename(
|
|
10385
|
-
return
|
|
10384
|
+
function getTypeFromFilename(path7) {
|
|
10385
|
+
return path7.slice((path7.lastIndexOf(".") - 1 >>> 0) + 2).toLowerCase();
|
|
10386
10386
|
}
|
|
10387
10387
|
function getRendererFromType(type) {
|
|
10388
10388
|
switch (type) {
|
|
@@ -10446,17 +10446,17 @@ var require_server = __commonJS({
|
|
|
10446
10446
|
const renderer = getRendererFromType(params.opts.type);
|
|
10447
10447
|
return render(renderer.renderToBuffer, text, params);
|
|
10448
10448
|
};
|
|
10449
|
-
exports.toFile = function toFile(
|
|
10450
|
-
if (typeof
|
|
10449
|
+
exports.toFile = function toFile(path7, text, opts, cb) {
|
|
10450
|
+
if (typeof path7 !== "string" || !(typeof text === "string" || typeof text === "object")) {
|
|
10451
10451
|
throw new Error("Invalid argument");
|
|
10452
10452
|
}
|
|
10453
10453
|
if (arguments.length < 3 && !canPromise()) {
|
|
10454
10454
|
throw new Error("Too few arguments provided");
|
|
10455
10455
|
}
|
|
10456
10456
|
const params = checkParams(text, opts, cb);
|
|
10457
|
-
const type = params.opts.type || getTypeFromFilename(
|
|
10457
|
+
const type = params.opts.type || getTypeFromFilename(path7);
|
|
10458
10458
|
const renderer = getRendererFromType(type);
|
|
10459
|
-
const renderToFile = renderer.renderToFile.bind(null,
|
|
10459
|
+
const renderToFile = renderer.renderToFile.bind(null, path7);
|
|
10460
10460
|
return render(renderToFile, text, params);
|
|
10461
10461
|
};
|
|
10462
10462
|
exports.toFileStream = function toFileStream(stream, text, opts) {
|
|
@@ -10655,9 +10655,9 @@ var init_mock_kernel = __esm({
|
|
|
10655
10655
|
});
|
|
10656
10656
|
|
|
10657
10657
|
// src/index.ts
|
|
10658
|
-
import
|
|
10658
|
+
import path6 from "node:path";
|
|
10659
10659
|
|
|
10660
|
-
// ../../node_modules/.pnpm/dsh-remote-wire@1.
|
|
10660
|
+
// ../../node_modules/.pnpm/dsh-remote-wire@1.3.0/node_modules/dsh-remote-wire/dist/src/crypto/bytes.js
|
|
10661
10661
|
import { Buffer as Buffer2 } from "node:buffer";
|
|
10662
10662
|
var encoder = new TextEncoder();
|
|
10663
10663
|
var decoder = new TextDecoder("utf-8", { fatal: false });
|
|
@@ -10684,7 +10684,7 @@ function concat(parts) {
|
|
|
10684
10684
|
return out;
|
|
10685
10685
|
}
|
|
10686
10686
|
|
|
10687
|
-
// ../../node_modules/.pnpm/dsh-remote-wire@1.
|
|
10687
|
+
// ../../node_modules/.pnpm/dsh-remote-wire@1.3.0/node_modules/dsh-remote-wire/dist/src/crypto/keys.js
|
|
10688
10688
|
import { createHash, randomBytes } from "node:crypto";
|
|
10689
10689
|
var KDF_NAMESPACE = "dsh-rc/v1";
|
|
10690
10690
|
var UNIT_SEPARATOR = 31;
|
|
@@ -10714,7 +10714,7 @@ function randomNonce() {
|
|
|
10714
10714
|
return new Uint8Array(randomBytes(NONCE_BYTES));
|
|
10715
10715
|
}
|
|
10716
10716
|
|
|
10717
|
-
// ../../node_modules/.pnpm/dsh-remote-wire@1.
|
|
10717
|
+
// ../../node_modules/.pnpm/dsh-remote-wire@1.3.0/node_modules/dsh-remote-wire/dist/src/crypto/record.js
|
|
10718
10718
|
var import_tweetnacl = __toESM(require_nacl_fast(), 1);
|
|
10719
10719
|
var MAC_BYTES = 16;
|
|
10720
10720
|
var MIN_RECORD_BYTES = NONCE_BYTES + MAC_BYTES;
|
|
@@ -10747,7 +10747,7 @@ function open(key, record2) {
|
|
|
10747
10747
|
}
|
|
10748
10748
|
}
|
|
10749
10749
|
|
|
10750
|
-
// ../../node_modules/.pnpm/dsh-remote-wire@1.
|
|
10750
|
+
// ../../node_modules/.pnpm/dsh-remote-wire@1.3.0/node_modules/dsh-remote-wire/dist/src/identity/pairing.js
|
|
10751
10751
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
10752
10752
|
var URI_PREFIX = "dshr:";
|
|
10753
10753
|
var TOKEN_RE = /^\d{6}$/;
|
|
@@ -11593,10 +11593,10 @@ function mergeDefs(...defs) {
|
|
|
11593
11593
|
function cloneDef(schema) {
|
|
11594
11594
|
return mergeDefs(schema._zod.def);
|
|
11595
11595
|
}
|
|
11596
|
-
function getElementAtPath(obj,
|
|
11597
|
-
if (!
|
|
11596
|
+
function getElementAtPath(obj, path7) {
|
|
11597
|
+
if (!path7)
|
|
11598
11598
|
return obj;
|
|
11599
|
-
return
|
|
11599
|
+
return path7.reduce((acc, key) => acc?.[key], obj);
|
|
11600
11600
|
}
|
|
11601
11601
|
function promiseAllObject(promisesObj) {
|
|
11602
11602
|
const keys = Object.keys(promisesObj);
|
|
@@ -11936,11 +11936,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
11936
11936
|
}
|
|
11937
11937
|
return false;
|
|
11938
11938
|
}
|
|
11939
|
-
function prefixIssues(
|
|
11939
|
+
function prefixIssues(path7, issues) {
|
|
11940
11940
|
return issues.map((iss) => {
|
|
11941
11941
|
var _a3;
|
|
11942
11942
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
11943
|
-
iss.path.unshift(
|
|
11943
|
+
iss.path.unshift(path7);
|
|
11944
11944
|
return iss;
|
|
11945
11945
|
});
|
|
11946
11946
|
}
|
|
@@ -12390,16 +12390,16 @@ function flattenError(error62, mapper = (issue2) => issue2.message) {
|
|
|
12390
12390
|
}
|
|
12391
12391
|
function formatError(error62, mapper = (issue2) => issue2.message) {
|
|
12392
12392
|
const fieldErrors = { _errors: [] };
|
|
12393
|
-
const processError = (error63,
|
|
12393
|
+
const processError = (error63, path7 = []) => {
|
|
12394
12394
|
for (const issue2 of error63.issues) {
|
|
12395
12395
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
12396
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
12396
|
+
issue2.errors.map((issues) => processError({ issues }, [...path7, ...issue2.path]));
|
|
12397
12397
|
} else if (issue2.code === "invalid_key") {
|
|
12398
|
-
processError({ issues: issue2.issues }, [...
|
|
12398
|
+
processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
|
|
12399
12399
|
} else if (issue2.code === "invalid_element") {
|
|
12400
|
-
processError({ issues: issue2.issues }, [...
|
|
12400
|
+
processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
|
|
12401
12401
|
} else {
|
|
12402
|
-
const fullpath = [...
|
|
12402
|
+
const fullpath = [...path7, ...issue2.path];
|
|
12403
12403
|
if (fullpath.length === 0) {
|
|
12404
12404
|
fieldErrors._errors.push(mapper(issue2));
|
|
12405
12405
|
} else {
|
|
@@ -12438,17 +12438,17 @@ function formatError(error62, mapper = (issue2) => issue2.message) {
|
|
|
12438
12438
|
}
|
|
12439
12439
|
function treeifyError(error62, mapper = (issue2) => issue2.message) {
|
|
12440
12440
|
const result2 = { errors: [] };
|
|
12441
|
-
const processError = (error63,
|
|
12441
|
+
const processError = (error63, path7 = []) => {
|
|
12442
12442
|
var _a3;
|
|
12443
12443
|
for (const issue2 of error63.issues) {
|
|
12444
12444
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
12445
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
12445
|
+
issue2.errors.map((issues) => processError({ issues }, [...path7, ...issue2.path]));
|
|
12446
12446
|
} else if (issue2.code === "invalid_key") {
|
|
12447
|
-
processError({ issues: issue2.issues }, [...
|
|
12447
|
+
processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
|
|
12448
12448
|
} else if (issue2.code === "invalid_element") {
|
|
12449
|
-
processError({ issues: issue2.issues }, [...
|
|
12449
|
+
processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
|
|
12450
12450
|
} else {
|
|
12451
|
-
const fullpath = [...
|
|
12451
|
+
const fullpath = [...path7, ...issue2.path];
|
|
12452
12452
|
if (fullpath.length === 0) {
|
|
12453
12453
|
result2.errors.push(mapper(issue2));
|
|
12454
12454
|
continue;
|
|
@@ -12487,8 +12487,8 @@ function treeifyError(error62, mapper = (issue2) => issue2.message) {
|
|
|
12487
12487
|
}
|
|
12488
12488
|
function toDotPath(_path) {
|
|
12489
12489
|
const segs = [];
|
|
12490
|
-
const
|
|
12491
|
-
for (const seg of
|
|
12490
|
+
const path7 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
12491
|
+
for (const seg of path7) {
|
|
12492
12492
|
if (typeof seg === "number")
|
|
12493
12493
|
segs.push(`[${seg}]`);
|
|
12494
12494
|
else if (typeof seg === "symbol")
|
|
@@ -29590,13 +29590,13 @@ function resolveRef(ref, ctx) {
|
|
|
29590
29590
|
if (!ref.startsWith("#")) {
|
|
29591
29591
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
29592
29592
|
}
|
|
29593
|
-
const
|
|
29594
|
-
if (
|
|
29593
|
+
const path7 = ref.slice(1).split("/").filter(Boolean);
|
|
29594
|
+
if (path7.length === 0) {
|
|
29595
29595
|
return ctx.rootSchema;
|
|
29596
29596
|
}
|
|
29597
29597
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
29598
|
-
if (
|
|
29599
|
-
const key =
|
|
29598
|
+
if (path7[0] === defsKey) {
|
|
29599
|
+
const key = path7[1] === void 0 ? void 0 : decodeJSONPointerSegment(path7[1]);
|
|
29600
29600
|
if (!key || !ctx.defs[key]) {
|
|
29601
29601
|
throw new Error(`Reference not found: ${ref}`);
|
|
29602
29602
|
}
|
|
@@ -30445,7 +30445,7 @@ function date4(params) {
|
|
|
30445
30445
|
return _coercedDate(ZodDate, params);
|
|
30446
30446
|
}
|
|
30447
30447
|
|
|
30448
|
-
// ../../node_modules/.pnpm/dsh-remote-wire@1.
|
|
30448
|
+
// ../../node_modules/.pnpm/dsh-remote-wire@1.3.0/node_modules/dsh-remote-wire/dist/src/wire/frames.js
|
|
30449
30449
|
var PAIRING_TOKEN_RE = /^\d{6}$/;
|
|
30450
30450
|
var nonEmpty = external_exports.string().min(1);
|
|
30451
30451
|
var pairingToken = external_exports.string().regex(PAIRING_TOKEN_RE);
|
|
@@ -30604,7 +30604,7 @@ function parseRelayFrameText(raw) {
|
|
|
30604
30604
|
}
|
|
30605
30605
|
}
|
|
30606
30606
|
|
|
30607
|
-
// ../../node_modules/.pnpm/dsh-remote-wire@1.
|
|
30607
|
+
// ../../node_modules/.pnpm/dsh-remote-wire@1.3.0/node_modules/dsh-remote-wire/dist/src/wire/payloads.js
|
|
30608
30608
|
var SESSION_STATES = [
|
|
30609
30609
|
"idle",
|
|
30610
30610
|
"running",
|
|
@@ -30767,12 +30767,28 @@ var evPayload = external_exports.discriminatedUnion("t", [
|
|
|
30767
30767
|
evResult,
|
|
30768
30768
|
evSessionHistory
|
|
30769
30769
|
]);
|
|
30770
|
+
var imageAttachment = external_exports.object({
|
|
30771
|
+
/** 落盘用的文件名(mp 侧生成,形如 `img-<ms>-<n>.jpg`;主机侧还会再收敛一次字符集)。 */
|
|
30772
|
+
name: nonEmpty2,
|
|
30773
|
+
mediaType: external_exports.literal("image/jpeg"),
|
|
30774
|
+
/** base64 字节,**不带** `data:` 前缀。 */
|
|
30775
|
+
data: nonEmpty2,
|
|
30776
|
+
/** 压缩后的像素尺寸,主机写旁车元数据用(排错时对得上)。 */
|
|
30777
|
+
width: external_exports.number().int().positive().optional(),
|
|
30778
|
+
height: external_exports.number().int().positive().optional()
|
|
30779
|
+
});
|
|
30770
30780
|
var cmdSendPrompt = external_exports.object({
|
|
30771
30781
|
t: external_exports.literal("cmd.send_prompt"),
|
|
30772
30782
|
cmdId: nonEmpty2,
|
|
30773
30783
|
/** DSH 会话 id,不是配对通道 id。 */
|
|
30774
30784
|
sessionId: nonEmpty2,
|
|
30775
|
-
text: external_exports.string()
|
|
30785
|
+
text: external_exports.string(),
|
|
30786
|
+
/**
|
|
30787
|
+
* 随消息的图片附件。**可选**:老版本手机不带这个字段,老主机看到也不认
|
|
30788
|
+
* (zod 默认 strip 未知键,而 text 照旧)——所以这是向后兼容的增补,不升协议版本。
|
|
30789
|
+
* 上限 4 张:再多对"看清楚这张图"没有帮助,只是把帧撑爆。
|
|
30790
|
+
*/
|
|
30791
|
+
images: external_exports.array(imageAttachment).max(4).optional()
|
|
30776
30792
|
});
|
|
30777
30793
|
var answerItem = external_exports.object({
|
|
30778
30794
|
questionId: nonEmpty2,
|
|
@@ -30861,7 +30877,7 @@ var PAYLOAD_TYPES = {
|
|
|
30861
30877
|
evSessionHistory: "ev.session_history"
|
|
30862
30878
|
};
|
|
30863
30879
|
|
|
30864
|
-
// ../../node_modules/.pnpm/dsh-remote-wire@1.
|
|
30880
|
+
// ../../node_modules/.pnpm/dsh-remote-wire@1.3.0/node_modules/dsh-remote-wire/dist/src/wire/outbound.js
|
|
30865
30881
|
function sessionChanged(sessions, reason) {
|
|
30866
30882
|
return { t: PAYLOAD_TYPES.evSessionChanged, sessions, ...reason === void 0 ? {} : { reason } };
|
|
30867
30883
|
}
|
|
@@ -30920,7 +30936,7 @@ function sessionHistory(args) {
|
|
|
30920
30936
|
};
|
|
30921
30937
|
}
|
|
30922
30938
|
|
|
30923
|
-
// ../../node_modules/.pnpm/dsh-remote-wire@1.
|
|
30939
|
+
// ../../node_modules/.pnpm/dsh-remote-wire@1.3.0/node_modules/dsh-remote-wire/dist/src/platform/sleep.js
|
|
30924
30940
|
function detectBackend(platform) {
|
|
30925
30941
|
if (platform === "darwin")
|
|
30926
30942
|
return "caffeinate";
|
|
@@ -30961,6 +30977,81 @@ function buildSleepCommand(platform, ownerPid, keepDisplay = false) {
|
|
|
30961
30977
|
// src/core/runtime.ts
|
|
30962
30978
|
import { randomUUID } from "node:crypto";
|
|
30963
30979
|
|
|
30980
|
+
// src/shell/uploads.ts
|
|
30981
|
+
import fs from "node:fs";
|
|
30982
|
+
import path from "node:path";
|
|
30983
|
+
function safeSegment(raw, fallback, maxLen = 96) {
|
|
30984
|
+
const cleaned = String(raw || "").replace(/[^A-Za-z0-9._-]+/g, "_").replace(/^[._-]+/, "").slice(0, maxLen).replace(/[._-]+$/, "");
|
|
30985
|
+
return cleaned === "" ? fallback : cleaned;
|
|
30986
|
+
}
|
|
30987
|
+
function decodeBase64(data) {
|
|
30988
|
+
if (!/^[A-Za-z0-9+/=\s]+$/.test(data)) return null;
|
|
30989
|
+
const buf = Buffer.from(data, "base64");
|
|
30990
|
+
return buf.length > 0 ? buf : null;
|
|
30991
|
+
}
|
|
30992
|
+
function looksLikeJpeg(buf) {
|
|
30993
|
+
return buf.length > 3 && buf[0] === 255 && buf[1] === 216 && buf[2] === 255;
|
|
30994
|
+
}
|
|
30995
|
+
function saveImageAttachments(options) {
|
|
30996
|
+
const maxCount = options.maxCount ?? 4;
|
|
30997
|
+
const maxBytes = options.maxBytesPerImage ?? 4 * 1024 * 1024;
|
|
30998
|
+
const images = options.images || [];
|
|
30999
|
+
if (images.length === 0) return { ok: true, saved: [], dir: options.dir };
|
|
31000
|
+
if (images.length > maxCount) {
|
|
31001
|
+
return { ok: false, message: `\u4E00\u6B21\u6700\u591A\u5E26 ${maxCount} \u5F20\u56FE\u7247\uFF0C\u6536\u5230 ${images.length} \u5F20` };
|
|
31002
|
+
}
|
|
31003
|
+
const decoded = [];
|
|
31004
|
+
for (const [i, img] of images.entries()) {
|
|
31005
|
+
if (img.mediaType !== "image/jpeg") {
|
|
31006
|
+
return { ok: false, message: `\u7B2C ${i + 1} \u5F20\u4E0D\u662F jpeg\uFF08${img.mediaType || "\u7A7A"}\uFF09\uFF0C\u4E3B\u673A\u53EA\u6536 jpeg` };
|
|
31007
|
+
}
|
|
31008
|
+
const buf = decodeBase64(img.data);
|
|
31009
|
+
if (!buf) return { ok: false, message: `\u7B2C ${i + 1} \u5F20\u7684\u89E3\u7801\u5931\u8D25\uFF08\u4E0D\u662F\u5408\u6CD5 base64\uFF09` };
|
|
31010
|
+
if (buf.length > maxBytes) {
|
|
31011
|
+
return {
|
|
31012
|
+
ok: false,
|
|
31013
|
+
message: `\u7B2C ${i + 1} \u5F20\u6709 ${Math.round(buf.length / 1024)}KB\uFF0C\u8D85\u8FC7\u5355\u5F20\u4E0A\u9650 ${Math.round(maxBytes / 1024)}KB`
|
|
31014
|
+
};
|
|
31015
|
+
}
|
|
31016
|
+
if (!looksLikeJpeg(buf)) {
|
|
31017
|
+
return { ok: false, message: `\u7B2C ${i + 1} \u5F20\u7684\u5185\u5BB9\u4E0D\u662F jpeg\uFF08\u6587\u4EF6\u5934\u5BF9\u4E0D\u4E0A\uFF09` };
|
|
31018
|
+
}
|
|
31019
|
+
decoded.push({ img, buf });
|
|
31020
|
+
}
|
|
31021
|
+
const sessionDir = path.join(options.dir, safeSegment(options.sessionId, "session"));
|
|
31022
|
+
const written = [];
|
|
31023
|
+
try {
|
|
31024
|
+
fs.mkdirSync(sessionDir, { recursive: true });
|
|
31025
|
+
for (const [i, one] of decoded.entries()) {
|
|
31026
|
+
const base = safeSegment(one.img.name, `img-${i + 1}.jpg`).replace(/\.jpg$/i, "") + ".jpg";
|
|
31027
|
+
let name = base;
|
|
31028
|
+
let n = 1;
|
|
31029
|
+
while (fs.existsSync(path.join(sessionDir, name))) {
|
|
31030
|
+
name = base.replace(/\.jpg$/, `-${++n}.jpg`);
|
|
31031
|
+
}
|
|
31032
|
+
const file2 = path.join(sessionDir, name);
|
|
31033
|
+
fs.writeFileSync(file2, one.buf, { mode: 384 });
|
|
31034
|
+
written.push({ name, path: file2, bytes: one.buf.length });
|
|
31035
|
+
}
|
|
31036
|
+
} catch (error62) {
|
|
31037
|
+
return {
|
|
31038
|
+
ok: false,
|
|
31039
|
+
message: `\u56FE\u7247\u843D\u76D8\u5931\u8D25\uFF1A${String(error62?.message ?? error62).slice(0, 160)}`
|
|
31040
|
+
};
|
|
31041
|
+
}
|
|
31042
|
+
return { ok: true, saved: written, dir: sessionDir };
|
|
31043
|
+
}
|
|
31044
|
+
function appendImageNote(text, saved) {
|
|
31045
|
+
if (saved.length === 0) return text;
|
|
31046
|
+
const lines = saved.map((img, i) => `${i + 1}. ${img.path}`);
|
|
31047
|
+
const note = `
|
|
31048
|
+
|
|
31049
|
+
[\u56FE\u7247\u9644\u4EF6 ${saved.length} \u5F20\uFF0C\u5DF2\u5B58\u5230\u672C\u673A]
|
|
31050
|
+
${lines.join("\n")}`;
|
|
31051
|
+
const head = String(text || "");
|
|
31052
|
+
return head === "" ? note.replace(/^\n\n/, "") : head + note;
|
|
31053
|
+
}
|
|
31054
|
+
|
|
30964
31055
|
// src/core/window.ts
|
|
30965
31056
|
var DEFAULT_WINDOW_OPTIONS = {
|
|
30966
31057
|
windowMs: 120,
|
|
@@ -31131,7 +31222,11 @@ var DEFAULTS = {
|
|
|
31131
31222
|
listingRefreshMs: 15e3,
|
|
31132
31223
|
approvalTimeoutMs: 18e4,
|
|
31133
31224
|
questionTimeoutMs: 3e5,
|
|
31134
|
-
unarchiveOnPrompt: true
|
|
31225
|
+
unarchiveOnPrompt: true,
|
|
31226
|
+
// 图片附件:默认**不收**(uploadDir 空 = 拒收)。要放开必须在插件配置里显式
|
|
31227
|
+
// 给一个目录——落盘是往用户磁盘写文件,不该由库默认值悄悄代劳。
|
|
31228
|
+
uploadDir: "",
|
|
31229
|
+
maxImageBytes: 4 * 1024 * 1024
|
|
31135
31230
|
};
|
|
31136
31231
|
var LISTING_LIMIT = 100;
|
|
31137
31232
|
var HISTORY_LIMIT = 40;
|
|
@@ -31218,7 +31313,32 @@ var HostRuntime = class {
|
|
|
31218
31313
|
return;
|
|
31219
31314
|
}
|
|
31220
31315
|
}
|
|
31221
|
-
|
|
31316
|
+
let text = cmd.text;
|
|
31317
|
+
const images = Array.isArray(cmd.images) ? cmd.images : [];
|
|
31318
|
+
if (images.length > 0) {
|
|
31319
|
+
if (!this.options.uploadDir) {
|
|
31320
|
+
reply(false, { message: "\u8FD9\u53F0\u4E3B\u673A\u6CA1\u914D\u56FE\u7247\u843D\u76D8\u76EE\u5F55\uFF08uploadDir\uFF09\uFF0C\u6536\u4E0D\u4E86\u56FE\u7247\u9644\u4EF6" });
|
|
31321
|
+
return;
|
|
31322
|
+
}
|
|
31323
|
+
const saved = saveImageAttachments({
|
|
31324
|
+
images,
|
|
31325
|
+
dir: this.options.uploadDir,
|
|
31326
|
+
sessionId: cmd.sessionId,
|
|
31327
|
+
maxBytesPerImage: this.options.maxImageBytes
|
|
31328
|
+
});
|
|
31329
|
+
if (!saved.ok) {
|
|
31330
|
+
reply(false, { message: saved.message });
|
|
31331
|
+
return;
|
|
31332
|
+
}
|
|
31333
|
+
this.options.log?.("\u56FE\u7247\u9644\u4EF6\u843D\u76D8", {
|
|
31334
|
+
sessionId: cmd.sessionId,
|
|
31335
|
+
images: saved.saved.length,
|
|
31336
|
+
bytes: saved.saved.reduce((sum, img) => sum + img.bytes, 0),
|
|
31337
|
+
dir: saved.dir
|
|
31338
|
+
});
|
|
31339
|
+
text = appendImageNote(text, saved.saved);
|
|
31340
|
+
}
|
|
31341
|
+
const sent = await this.kernel.sendPrompt(cmd.sessionId, text);
|
|
31222
31342
|
reply(sent.ok, sent.message ? { message: sent.message } : {});
|
|
31223
31343
|
if (sent.ok) {
|
|
31224
31344
|
this.sleep.markActive();
|
|
@@ -31567,9 +31687,11 @@ var HostRuntime = class {
|
|
|
31567
31687
|
* 再补一帧 `ev.run_state` 兜住"手机上装的是老版小程序"这一档。
|
|
31568
31688
|
*
|
|
31569
31689
|
* 为什么要两条而不是一条:`ev.permission_resolved` / `ev.question_resolved` 是按
|
|
31570
|
-
* `requestId`
|
|
31571
|
-
*
|
|
31572
|
-
*
|
|
31690
|
+
* `requestId` 收单的(一次答完不会误收别的会话、别的请求那张卡),这是**正路**——
|
|
31691
|
+
* mp 1.0.1 起就认这两帧(`pages/chat/chat.js` 的 `_onPermissionResolved` /
|
|
31692
|
+
* `_onQuestionResolved`)。而 `ev.run_state` 是它从第一版就认的粗粒度信号
|
|
31693
|
+
* (整会话两张卡一起收),发它只为兜住 **1.0.1 以前**的安装存量——那一档小程序
|
|
31694
|
+
* 的分发是一串 `if (p.t === …)`,认不出来的 `t` 静默忽略。
|
|
31573
31695
|
* (`pages/chat/chat.js` 的 `_onRunState` 同时清 `pendingPermission` 与 `pendingQuestion`,
|
|
31574
31696
|
* 并停掉那条还在走的本地倒数)。所以两条都发:新版手机收到精确帧就精收一张,
|
|
31575
31697
|
* 老版手机靠 `run_state` 也能当场收卡,不用等用户重新上传小程序。
|
|
@@ -33218,12 +33340,6 @@ function createServicesKernel(services, options) {
|
|
|
33218
33340
|
modelFace: modelFaceSummary(),
|
|
33219
33341
|
workspaceRegistry: typeof services.workspaceRegistry === "object",
|
|
33220
33342
|
userQuestions: typeof services.userQuestions === "object",
|
|
33221
|
-
// 这个键**已经不生效**了:提问现在跟审批一样是 waterfall 参与者,两端同弹、
|
|
33222
|
-
// 谁先答谁算,不再有"接管/取代桌面"这回事(那条 `registerProvider` 单提供者
|
|
33223
|
-
// 路线在这一代宿主上根本不存在)。这里照实把配置值报出来,真正的状态看
|
|
33224
|
-
// `questionsFace`。(删键要动 config.ts/index.ts,那两棵树此刻有并行会话在飞的改动。)
|
|
33225
|
-
takeOverQuestions: options.takeOverQuestions === true,
|
|
33226
|
-
takeOverQuestionsInert: options.takeOverQuestions === true,
|
|
33227
33343
|
archivedSessions: archivedIds().size,
|
|
33228
33344
|
hasOn: typeof services.on === "function",
|
|
33229
33345
|
// 真机排错的第一现场:内核到底发了哪些事件类型、其中哪些我们没认。
|
|
@@ -33576,7 +33692,7 @@ function createOneShotTimers(clock) {
|
|
|
33576
33692
|
|
|
33577
33693
|
// src/shell/status.ts
|
|
33578
33694
|
import { mkdirSync, renameSync, writeFileSync } from "node:fs";
|
|
33579
|
-
import
|
|
33695
|
+
import path2 from "node:path";
|
|
33580
33696
|
var StatusFile = class {
|
|
33581
33697
|
constructor(file2, clock, refreshMs = 3e3) {
|
|
33582
33698
|
this.file = file2;
|
|
@@ -33590,7 +33706,7 @@ var StatusFile = class {
|
|
|
33590
33706
|
write(snapshot) {
|
|
33591
33707
|
if (!this.file) return;
|
|
33592
33708
|
try {
|
|
33593
|
-
mkdirSync(
|
|
33709
|
+
mkdirSync(path2.dirname(this.file), { recursive: true });
|
|
33594
33710
|
const tmp = `${this.file}.tmp-${process.pid}`;
|
|
33595
33711
|
writeFileSync(
|
|
33596
33712
|
tmp,
|
|
@@ -33633,7 +33749,7 @@ var StatusFile = class {
|
|
|
33633
33749
|
// src/shell/host-id.ts
|
|
33634
33750
|
import { randomBytes as randomBytes4 } from "node:crypto";
|
|
33635
33751
|
import { chmodSync, mkdirSync as mkdirSync2, readFileSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
33636
|
-
import
|
|
33752
|
+
import path3 from "node:path";
|
|
33637
33753
|
var HOST_ID = /^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$/;
|
|
33638
33754
|
function newHostId() {
|
|
33639
33755
|
return `drc-${randomBytes4(6).toString("hex")}`;
|
|
@@ -33641,7 +33757,7 @@ function newHostId() {
|
|
|
33641
33757
|
function resolveHostId(dir, configured) {
|
|
33642
33758
|
if (configured) return configured;
|
|
33643
33759
|
if (!dir) return newHostId();
|
|
33644
|
-
const file2 =
|
|
33760
|
+
const file2 = path3.join(dir, "host-id");
|
|
33645
33761
|
let existing;
|
|
33646
33762
|
try {
|
|
33647
33763
|
existing = readFileSync(file2, "utf8").trim();
|
|
@@ -33673,7 +33789,7 @@ function resolveHostId(dir, configured) {
|
|
|
33673
33789
|
// src/shell/pair-store.ts
|
|
33674
33790
|
import { chmodSync as chmodSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
33675
33791
|
import { createHash as createHash2 } from "node:crypto";
|
|
33676
|
-
import
|
|
33792
|
+
import path4 from "node:path";
|
|
33677
33793
|
var storedConversationSchema = external_exports.object({
|
|
33678
33794
|
id: external_exports.string().min(1),
|
|
33679
33795
|
/** 配对 PSK(base64)。两把方向密钥在恢复时由它现派生,不落盘。 */
|
|
@@ -33691,14 +33807,14 @@ var storeSchema = external_exports.object({
|
|
|
33691
33807
|
savedAt: external_exports.number().finite().nonnegative(),
|
|
33692
33808
|
conversations: external_exports.array(storedConversationSchema)
|
|
33693
33809
|
});
|
|
33694
|
-
function
|
|
33810
|
+
function safeSegment2(hostId) {
|
|
33695
33811
|
const cleaned = hostId.replace(/[^A-Za-z0-9._-]/g, "_").slice(0, 48);
|
|
33696
33812
|
const tag = createHash2("sha256").update(hostId).digest("hex").slice(0, 8);
|
|
33697
33813
|
return `${cleaned || "host"}-${tag}`;
|
|
33698
33814
|
}
|
|
33699
33815
|
function defaultPairStoreFile(statusFile, hostId) {
|
|
33700
33816
|
if (!statusFile) return "";
|
|
33701
|
-
return
|
|
33817
|
+
return path4.join(path4.dirname(statusFile), `conversations-${safeSegment2(hostId)}.json`);
|
|
33702
33818
|
}
|
|
33703
33819
|
var PairStore = class {
|
|
33704
33820
|
constructor(options) {
|
|
@@ -33768,7 +33884,7 @@ var PairStore = class {
|
|
|
33768
33884
|
const body = JSON.stringify({ version: 1, hostId, savedAt: now, conversations }) + "\n";
|
|
33769
33885
|
const tmp = `${file2}.tmp-${process.pid}`;
|
|
33770
33886
|
try {
|
|
33771
|
-
mkdirSync3(
|
|
33887
|
+
mkdirSync3(path4.dirname(file2), { recursive: true });
|
|
33772
33888
|
writeFileSync3(tmp, body, { encoding: "utf8", mode: 384 });
|
|
33773
33889
|
chmodSync2(tmp, 384);
|
|
33774
33890
|
renameSync2(tmp, file2);
|
|
@@ -33797,7 +33913,7 @@ function safeJsonParse(raw) {
|
|
|
33797
33913
|
|
|
33798
33914
|
// src/shell/config.ts
|
|
33799
33915
|
import { homedir } from "node:os";
|
|
33800
|
-
import
|
|
33916
|
+
import path5 from "node:path";
|
|
33801
33917
|
var DEFAULT_CONFIG = {
|
|
33802
33918
|
enabled: true,
|
|
33803
33919
|
serverUrl: "ws://127.0.0.1:8787",
|
|
@@ -33807,12 +33923,11 @@ var DEFAULT_CONFIG = {
|
|
|
33807
33923
|
hostLabel: "dsh-host",
|
|
33808
33924
|
keepAwake: { enabled: true, idleReleaseSec: 300, keepDisplay: false },
|
|
33809
33925
|
mockBridge: false,
|
|
33810
|
-
statusFile:
|
|
33926
|
+
statusFile: path5.join(homedir(), ".dsh", "dsh-remote-control", "status.json"),
|
|
33811
33927
|
unarchiveOnPrompt: true,
|
|
33812
33928
|
pairOnStartSec: 0,
|
|
33813
33929
|
pairTtlMs: 12e4,
|
|
33814
33930
|
carrierGraceMs: 5e3,
|
|
33815
|
-
takeOverQuestions: false,
|
|
33816
33931
|
approvalTimeoutSec: 180,
|
|
33817
33932
|
listingRefreshSec: 15,
|
|
33818
33933
|
conversationIdleTtlSec: 86400,
|
|
@@ -33820,6 +33935,9 @@ var DEFAULT_CONFIG = {
|
|
|
33820
33935
|
restoredIdleTtlSec: 604800,
|
|
33821
33936
|
// 密钥簿落盘:默认跟着 statusFile 走(见 `resolvePairStoreFile`)。
|
|
33822
33937
|
pairStoreFile: "",
|
|
33938
|
+
// 图片附件落盘:默认 status.json 同目录的 uploads/(见 `resolveUploadDir`)。
|
|
33939
|
+
uploadDir: "",
|
|
33940
|
+
maxImageBytes: 4 * 1024 * 1024,
|
|
33823
33941
|
// 配对的唯一入口。关掉它 = 这台主机**没有**配对入口(`/drc pair` 与文本二维码都在
|
|
33824
33942
|
// 2026-10-03 删掉了),所以 index.ts 会把它记成一条 warn 而不是安静地什么都不做。
|
|
33825
33943
|
pill: { enabled: true }
|
|
@@ -33831,7 +33949,17 @@ function resolvePairStoreFile(config2, hostId) {
|
|
|
33831
33949
|
if (!configured) return defaultPairStoreFile(config2.statusFile, hostId);
|
|
33832
33950
|
if (configured.startsWith("/")) return configured;
|
|
33833
33951
|
if (!config2.statusFile) return configured;
|
|
33834
|
-
return
|
|
33952
|
+
return path5.join(path5.dirname(config2.statusFile), configured);
|
|
33953
|
+
}
|
|
33954
|
+
function resolveUploadDir(config2) {
|
|
33955
|
+
const configured = config2.uploadDir.trim();
|
|
33956
|
+
if (!configured) {
|
|
33957
|
+
const base = config2.statusFile ? path5.dirname(config2.statusFile) : path5.join(homedir(), ".dsh", "dsh-remote-control");
|
|
33958
|
+
return path5.join(base, "uploads");
|
|
33959
|
+
}
|
|
33960
|
+
if (configured.startsWith("/")) return configured;
|
|
33961
|
+
if (!config2.statusFile) return configured;
|
|
33962
|
+
return path5.join(path5.dirname(config2.statusFile), configured);
|
|
33835
33963
|
}
|
|
33836
33964
|
var loopback = /^wss?:\/\/(localhost|127\.0\.0\.1|\[::1\])(:|\/|$)/;
|
|
33837
33965
|
var wsUrl = /^wss?:\/\/.+/;
|
|
@@ -33860,7 +33988,6 @@ function readConfig(injected, env = process.env) {
|
|
|
33860
33988
|
if (fromEnv("DRC_PAIR_ON_START_SEC")) merged.pairOnStartSec = envSeconds(env.DRC_PAIR_ON_START_SEC);
|
|
33861
33989
|
if (fromEnv("DRC_PILL")) merged.pill.enabled = envFlag(env.DRC_PILL, merged.pill.enabled);
|
|
33862
33990
|
if (fromEnv("DRC_MOCK_BRIDGE") === "1") merged.mockBridge = true;
|
|
33863
|
-
if (fromEnv("DRC_TAKE_OVER_QUESTIONS") === "1") merged.takeOverQuestions = true;
|
|
33864
33991
|
if (merged.hostTokenEnv) merged.hostToken = env[merged.hostTokenEnv] ?? merged.hostToken;
|
|
33865
33992
|
return merged;
|
|
33866
33993
|
}
|
|
@@ -33935,13 +34062,6 @@ function validateConfig(config2) {
|
|
|
33935
34062
|
if (!config2.statusFile) {
|
|
33936
34063
|
problems.push({ level: "warn", field: "statusFile", message: "\u4E3A\u7A7A\u5C06\u5173\u95ED\u72B6\u6001\u5FEB\u7167\uFF1BGUI \u5BBF\u4E3B\u91CC\u8FD9\u662F\u552F\u4E00\u7684\u6392\u9519\u5165\u53E3" });
|
|
33937
34064
|
}
|
|
33938
|
-
if (config2.takeOverQuestions) {
|
|
33939
|
-
problems.push({
|
|
33940
|
-
level: "warn",
|
|
33941
|
-
field: "takeOverQuestions",
|
|
33942
|
-
message: "\u63D0\u95EE\u63A5\u7BA1\u4F1A**\u53D6\u4EE3\u684C\u9762 UI \u7684\u63D0\u95EE\u80FD\u529B**\uFF08ctx.userQuestions \u53EA\u5141\u8BB8\u4E00\u4E2A\u6D3B\u8DC3 provider\uFF09\uFF1B\u624B\u673A\u7AEF\u4E0D\u5728\u7EBF\u65F6\u63D0\u95EE\u4F1A\u76F4\u63A5\u5931\u8D25"
|
|
33943
|
-
});
|
|
33944
|
-
}
|
|
33945
34065
|
return problems;
|
|
33946
34066
|
}
|
|
33947
34067
|
function redact(value) {
|
|
@@ -34098,6 +34218,7 @@ function pillStatusHandler(deps) {
|
|
|
34098
34218
|
json2(response, 200, {
|
|
34099
34219
|
relay: status.relay,
|
|
34100
34220
|
paired: status.paired,
|
|
34221
|
+
pairings: status.pairings,
|
|
34101
34222
|
serverUrl: status.serverUrl,
|
|
34102
34223
|
version: status.version,
|
|
34103
34224
|
waiting: status.waiting,
|
|
@@ -34261,7 +34382,7 @@ function startPill(ctx, deps) {
|
|
|
34261
34382
|
}
|
|
34262
34383
|
|
|
34263
34384
|
// src/version.ts
|
|
34264
|
-
var PLUGIN_VERSION = true ? "2.0.
|
|
34385
|
+
var PLUGIN_VERSION = true ? "2.0.1" : "dev";
|
|
34265
34386
|
|
|
34266
34387
|
// src/index.ts
|
|
34267
34388
|
var SERVICE_NAMES = [
|
|
@@ -34317,7 +34438,7 @@ function applyInner(ctx, injected) {
|
|
|
34317
34438
|
const clock = systemClock;
|
|
34318
34439
|
const oneShot = createOneShotTimers(clock);
|
|
34319
34440
|
const status = new StatusFile(config2.statusFile, clock);
|
|
34320
|
-
const hostId = resolveHostId(config2.statusFile ?
|
|
34441
|
+
const hostId = resolveHostId(config2.statusFile ? path6.dirname(config2.statusFile) : "", config2.hostId);
|
|
34321
34442
|
const log = (message, fields = {}) => {
|
|
34322
34443
|
try {
|
|
34323
34444
|
process.stdout.write(
|
|
@@ -34441,6 +34562,8 @@ function applyInner(ctx, injected) {
|
|
|
34441
34562
|
runtime = new HostRuntime(port, transport, sleep, clock, {
|
|
34442
34563
|
listingRefreshMs: config2.listingRefreshSec * 1e3,
|
|
34443
34564
|
unarchiveOnPrompt: config2.unarchiveOnPrompt,
|
|
34565
|
+
uploadDir: resolveUploadDir(config2),
|
|
34566
|
+
maxImageBytes: config2.maxImageBytes,
|
|
34444
34567
|
approvalTimeoutMs: config2.approvalTimeoutSec * 1e3,
|
|
34445
34568
|
log: (message, fields) => log(message, fields)
|
|
34446
34569
|
});
|
|
@@ -34571,12 +34694,14 @@ function applyInner(ctx, injected) {
|
|
|
34571
34694
|
function currentPairing() {
|
|
34572
34695
|
const shown = active.pairing;
|
|
34573
34696
|
if (!shown) return null;
|
|
34574
|
-
|
|
34575
|
-
|
|
34697
|
+
const slot = slots.resolveFor(shown.token);
|
|
34698
|
+
if (!slot) return null;
|
|
34699
|
+
return { qr: shown.qr, token: shown.token, expiresAt: slot.expiresAt };
|
|
34576
34700
|
}
|
|
34577
34701
|
function ensureFreshPairing() {
|
|
34578
34702
|
const fresh = currentPairing() ?? createPairing();
|
|
34579
34703
|
if (!fresh) return null;
|
|
34704
|
+
if (fresh.expiresAt <= Date.now()) return createPairing();
|
|
34580
34705
|
return { qr: fresh.qr, token: fresh.token, expiresAt: fresh.expiresAt };
|
|
34581
34706
|
}
|
|
34582
34707
|
function pillStatus() {
|
|
@@ -34584,6 +34709,11 @@ function applyInner(ctx, injected) {
|
|
|
34584
34709
|
return {
|
|
34585
34710
|
relay: relay ? relayState() : "idle",
|
|
34586
34711
|
paired: relay?.clientCount ?? 0,
|
|
34712
|
+
// 配对簿里几条会话 = 配对还在不在。为什么必须与 paired 分开:pair-store 之后
|
|
34713
|
+
// 配对按 D3 长存、落盘,手机退后台只是 socket 断——只用 clientCount 回答 配没配上,
|
|
34714
|
+
// 用户把小程序放进后台的每一分钟,桌面那颗 pill 都会说 未配对,点开还会烧一张
|
|
34715
|
+
// 不需要的新码(2026-10-04 用户报的误解)。
|
|
34716
|
+
pairings: relay?.conversationCount ?? 0,
|
|
34587
34717
|
serverUrl: config2.serverUrl,
|
|
34588
34718
|
version: PLUGIN_VERSION,
|
|
34589
34719
|
waiting: waiting.count,
|
|
@@ -34625,7 +34755,7 @@ function applyInner(ctx, injected) {
|
|
|
34625
34755
|
return;
|
|
34626
34756
|
}
|
|
34627
34757
|
decided = true;
|
|
34628
|
-
start(createServicesKernel(collected, { log,
|
|
34758
|
+
start(createServicesKernel(collected, { log, clock }));
|
|
34629
34759
|
return;
|
|
34630
34760
|
}
|
|
34631
34761
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-remote-control",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "DSH Remote Control host plugin: pairs a running DeepSeek Harness with the DRC relay so a WeChat Mini Program can send prompts, watch streamed output, and answer approvals. Payload-level E2E encryption; the relay never sees plaintext. Pairing is one click on the status-bar pill (three same-origin routes + a browser half).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"provenance": true
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"dsh-remote-wire": "^1.
|
|
56
|
+
"dsh-remote-wire": "^1.3.0",
|
|
57
57
|
"qrcode": "^1.5.4",
|
|
58
58
|
"tweetnacl": "^1.0.3",
|
|
59
59
|
"ws": "^8.18.0",
|