dsh-remote-control 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cordis.patch.yml +6 -0
- package/dist/bundle/client.cjs +146 -0
- package/dist/bundle/index.js +667 -264
- package/package.json +13 -6
- package/dist/src/core/clock.d.ts +0 -45
- package/dist/src/core/clock.js +0 -83
- package/dist/src/core/clock.js.map +0 -1
- package/dist/src/core/keys.d.ts +0 -98
- package/dist/src/core/keys.js +0 -176
- package/dist/src/core/keys.js.map +0 -1
- package/dist/src/core/pairing-window.d.ts +0 -95
- package/dist/src/core/pairing-window.js +0 -92
- package/dist/src/core/pairing-window.js.map +0 -1
- package/dist/src/core/runtime.d.ts +0 -104
- package/dist/src/core/runtime.js +0 -491
- package/dist/src/core/runtime.js.map +0 -1
- package/dist/src/core/sleep-policy.d.ts +0 -81
- package/dist/src/core/sleep-policy.js +0 -134
- package/dist/src/core/sleep-policy.js.map +0 -1
- package/dist/src/core/window.d.ts +0 -88
- package/dist/src/core/window.js +0 -185
- package/dist/src/core/window.js.map +0 -1
- package/dist/src/index.d.ts +0 -70
- package/dist/src/index.js +0 -882
- package/dist/src/index.js.map +0 -1
- package/dist/src/platform/carrier-services.d.ts +0 -96
- package/dist/src/platform/carrier-services.js +0 -982
- package/dist/src/platform/carrier-services.js.map +0 -1
- package/dist/src/platform/guard.d.ts +0 -60
- package/dist/src/platform/guard.js +0 -124
- package/dist/src/platform/guard.js.map +0 -1
- package/dist/src/platform/mock-kernel.d.ts +0 -95
- package/dist/src/platform/mock-kernel.js +0 -180
- package/dist/src/platform/mock-kernel.js.map +0 -1
- package/dist/src/platform/qr.d.ts +0 -28
- package/dist/src/platform/qr.js +0 -80
- package/dist/src/platform/qr.js.map +0 -1
- package/dist/src/platform/sleep-posix.d.ts +0 -17
- package/dist/src/platform/sleep-posix.js +0 -91
- package/dist/src/platform/sleep-posix.js.map +0 -1
- package/dist/src/ports/index.d.ts +0 -246
- package/dist/src/ports/index.js +0 -2
- package/dist/src/ports/index.js.map +0 -1
- package/dist/src/shell/config.d.ts +0 -56
- package/dist/src/shell/config.js +0 -212
- package/dist/src/shell/config.js.map +0 -1
- package/dist/src/shell/pairing-text.d.ts +0 -38
- package/dist/src/shell/pairing-text.js +0 -22
- package/dist/src/shell/pairing-text.js.map +0 -1
- package/dist/src/shell/status.d.ts +0 -39
- package/dist/src/shell/status.js +0 -119
- package/dist/src/shell/status.js.map +0 -1
- package/dist/src/transport/relay.d.ts +0 -107
- package/dist/src/transport/relay.js +0 -359
- package/dist/src/transport/relay.js.map +0 -1
- package/dist/tests/carrier-events.test.d.ts +0 -1
- package/dist/tests/carrier-events.test.js +0 -88
- package/dist/tests/carrier-events.test.js.map +0 -1
- package/dist/tests/carrier-services.test.d.ts +0 -1
- package/dist/tests/carrier-services.test.js +0 -562
- package/dist/tests/carrier-services.test.js.map +0 -1
- package/dist/tests/carrier-vocabulary.test.d.ts +0 -1
- package/dist/tests/carrier-vocabulary.test.js +0 -149
- package/dist/tests/carrier-vocabulary.test.js.map +0 -1
- package/dist/tests/clock-probe-timers.test.d.ts +0 -1
- package/dist/tests/clock-probe-timers.test.js +0 -73
- package/dist/tests/clock-probe-timers.test.js.map +0 -1
- package/dist/tests/command-result.test.d.ts +0 -1
- package/dist/tests/command-result.test.js +0 -185
- package/dist/tests/command-result.test.js.map +0 -1
- package/dist/tests/config.test.d.ts +0 -1
- package/dist/tests/config.test.js +0 -223
- package/dist/tests/config.test.js.map +0 -1
- package/dist/tests/guard.test.d.ts +0 -1
- package/dist/tests/guard.test.js +0 -175
- package/dist/tests/guard.test.js.map +0 -1
- package/dist/tests/ids-and-keys.test.d.ts +0 -1
- package/dist/tests/ids-and-keys.test.js +0 -211
- package/dist/tests/ids-and-keys.test.js.map +0 -1
- package/dist/tests/pairing-text.test.d.ts +0 -1
- package/dist/tests/pairing-text.test.js +0 -62
- package/dist/tests/pairing-text.test.js.map +0 -1
- package/dist/tests/pairing-window.test.d.ts +0 -1
- package/dist/tests/pairing-window.test.js +0 -165
- package/dist/tests/pairing-window.test.js.map +0 -1
- package/dist/tests/relay-client.test.d.ts +0 -1
- package/dist/tests/relay-client.test.js +0 -557
- package/dist/tests/relay-client.test.js.map +0 -1
- package/dist/tests/runtime.test.d.ts +0 -1
- package/dist/tests/runtime.test.js +0 -963
- package/dist/tests/runtime.test.js.map +0 -1
- package/dist/tests/sleep.test.d.ts +0 -1
- package/dist/tests/sleep.test.js +0 -264
- package/dist/tests/sleep.test.js.map +0 -1
- package/dist/tests/status.test.d.ts +0 -1
- package/dist/tests/status.test.js +0 -238
- package/dist/tests/status.test.js.map +0 -1
- package/dist/tests/window.test.d.ts +0 -1
- package/dist/tests/window.test.js +0 -210
- package/dist/tests/window.test.js.map +0 -1
package/dist/src/platform/qr.js
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* qr — 配对二维码:矩阵来自 `qrcode`(node-qrcode),呈现层自己写。
|
|
3
|
-
*
|
|
4
|
-
* 为什么不自己写编码器:旧实现试过,被第三方解码器对拍抓出码字层的系统性差异后否决
|
|
5
|
-
* (取证 packages/plugin 旧 qr.ts 文件头,基线 b026d63:packages/plugin/src/qr.ts:5-9)。
|
|
6
|
-
* node-qrcode 的实测结论在 docs/legacy-spec/open-source-options.md §A.3:
|
|
7
|
-
* 真实配对 URI(98 B 典型 / 188 B 最坏)在 L/M/Q/H 四档纠错、12 组尺寸下全部被
|
|
8
|
-
* zxing 解出,CJK 载荷 round-trip 正确,纯 JS 无原生模块。
|
|
9
|
-
*
|
|
10
|
-
* 呈现层必须自己写的原因:宿主的 TUI 五花八门——有的会吞连续空格、有的没有方块字形、
|
|
11
|
-
* 有的用比例字体。所以默认样式是 `ascii`(`##` / `..`,每个亮模块都占一个真实字形),
|
|
12
|
-
* 它在任何渲染器下都不会错位。`half` 最紧凑但最脆。
|
|
13
|
-
*
|
|
14
|
-
* 一个终端格子大约是"高 = 2×宽",所以每个模块画两个字符宽,否则二维码会被拉成长方形,
|
|
15
|
-
* 手机很难对上焦。
|
|
16
|
-
*/
|
|
17
|
-
import QRCode from 'qrcode';
|
|
18
|
-
/** 取二维码的布尔矩阵(含静默区)。 */
|
|
19
|
-
export async function qrMatrix(text, ecc = 'M', quietZone = 2) {
|
|
20
|
-
const qr = QRCode.create(text, { errorCorrectionLevel: ecc });
|
|
21
|
-
const size = qr.modules.size;
|
|
22
|
-
const total = size + quietZone * 2;
|
|
23
|
-
const out = [];
|
|
24
|
-
for (let y = 0; y < total; y++) {
|
|
25
|
-
const row = [];
|
|
26
|
-
for (let x = 0; x < total; x++) {
|
|
27
|
-
const mx = x - quietZone;
|
|
28
|
-
const my = y - quietZone;
|
|
29
|
-
const dark = mx >= 0 && mx < size && my >= 0 && my < size && Boolean(qr.modules.get(my, mx));
|
|
30
|
-
row.push(dark);
|
|
31
|
-
}
|
|
32
|
-
out.push(row);
|
|
33
|
-
}
|
|
34
|
-
return out;
|
|
35
|
-
}
|
|
36
|
-
/** 渲染成终端文本。 */
|
|
37
|
-
export async function renderTerminalQr(text, options = {}) {
|
|
38
|
-
const { ecc = 'M', quietZone = 2, style = 'ascii', ansi = false } = options;
|
|
39
|
-
const matrix = await qrMatrix(text, ecc, quietZone);
|
|
40
|
-
let body;
|
|
41
|
-
if (style === 'half') {
|
|
42
|
-
const lines = [];
|
|
43
|
-
for (let y = 0; y < matrix.length; y += 2) {
|
|
44
|
-
const top = matrix[y];
|
|
45
|
-
const bottom = (matrix[y + 1] ?? top.map(() => false));
|
|
46
|
-
let line = '';
|
|
47
|
-
for (let x = 0; x < top.length; x++) {
|
|
48
|
-
line += top[x] && bottom[x] ? '█' : top[x] ? '▀' : bottom[x] ? '▄' : ' ';
|
|
49
|
-
}
|
|
50
|
-
lines.push(line);
|
|
51
|
-
}
|
|
52
|
-
body = lines.join('\n');
|
|
53
|
-
}
|
|
54
|
-
else {
|
|
55
|
-
const dark = style === 'ascii' ? '##' : '██';
|
|
56
|
-
const light = style === 'ascii' ? '..' : ' ';
|
|
57
|
-
body = matrix.map((row) => row.map((cell) => (cell ? dark : light)).join('')).join('\n');
|
|
58
|
-
}
|
|
59
|
-
return ansi ? `\x1b[30;107m${body}\x1b[0m` : body;
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* 生成 PNG。
|
|
63
|
-
*
|
|
64
|
-
* 为什么这是配对二维码的**首选输出**:DSH 的命令 API 只接受纯文本结果
|
|
65
|
-
* (`{kind, text}`,没有图片或附件类型),所以命令里没法把图交给 TUI;
|
|
66
|
-
* 但插件跑在主机上,可以直接写一个 PNG 并把它打开——真图像永远扫得出来。
|
|
67
|
-
*/
|
|
68
|
-
export async function qrPng(text, options = {}) {
|
|
69
|
-
return QRCode.toBuffer(text, {
|
|
70
|
-
errorCorrectionLevel: options.ecc ?? 'M',
|
|
71
|
-
margin: options.quietZone ?? 4,
|
|
72
|
-
scale: options.scale ?? 8,
|
|
73
|
-
type: 'png',
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
/** 二维码的模块数(测试用来断言静默区与几何,不依赖肉眼)。 */
|
|
77
|
-
export async function qrModuleCount(text, ecc = 'M') {
|
|
78
|
-
return QRCode.create(text, { errorCorrectionLevel: ecc }).modules.size;
|
|
79
|
-
}
|
|
80
|
-
//# sourceMappingURL=qr.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"qr.js","sourceRoot":"","sources":["../../../src/platform/qr.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type { SleepPort } from '../ports/index.js';
|
|
2
|
-
export declare class SystemSleepBackend implements SleepPort {
|
|
3
|
-
private child;
|
|
4
|
-
private lastError;
|
|
5
|
-
/** 平台名是构造时定下的,不与接口方法 `platform()` 同名。 */
|
|
6
|
-
private readonly osName;
|
|
7
|
-
constructor(platform?: string);
|
|
8
|
-
backend(): string;
|
|
9
|
-
platform(): string;
|
|
10
|
-
isActive(): boolean;
|
|
11
|
-
start(ownerPid: number, keepDisplay: boolean): {
|
|
12
|
-
ok: boolean;
|
|
13
|
-
message?: string;
|
|
14
|
-
};
|
|
15
|
-
stop(): void;
|
|
16
|
-
get error(): string | undefined;
|
|
17
|
-
}
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* sleep-posix — `SleepPort` 的系统工具实现(macOS `caffeinate` / Linux `systemd-inhibit`)。
|
|
3
|
-
*
|
|
4
|
-
* 为什么用外部命令而不是自研或引 npm 库:第三方睡眠抑制库本质也是 spawn 这两个工具,
|
|
5
|
-
* 而直接 spawn 换来的是"锁的生命周期可以由 pid 绑定来表达"。
|
|
6
|
-
*
|
|
7
|
-
* 三处必须留住的细节(都出自取证 docs/legacy-spec/relay-and-wireformat.md §6):
|
|
8
|
-
* - macOS 带 `-w <pid>`:**断言寿命绑到宿主进程**,宿主崩了锁随之消失,
|
|
9
|
-
* 不会留下一台永远不睡机的机器;整套方案不需要 sudo。
|
|
10
|
-
* - 子进程 `stdio:'ignore'` + `unref()`:插件跑在 GUI 宿主进程里,
|
|
11
|
-
* 不 unref 会吊住事件循环,不 ignore 会让 caffeinate 的输出污染宿主 stdout。
|
|
12
|
-
* - 失败原因(spawn error 或 exit code)要能被上层拿到,最终进
|
|
13
|
-
* `ev.keep_awake_state.reason`,手机上看得到"为什么没锁上"。
|
|
14
|
-
*
|
|
15
|
-
* Windows 不实现(本版明确不做,见 docs/DESIGN.md §7.2):只有一个从未在真机验证过的
|
|
16
|
-
* 内联 powershell 构造器,等于把验证不了的代码写进仓库。这里返回 unsupported,
|
|
17
|
-
* 手机端与 status.json 都会如实显示。
|
|
18
|
-
*/
|
|
19
|
-
import { spawn } from 'node:child_process';
|
|
20
|
-
import { buildSleepCommand, detectBackend, isSleepSupported } from 'dsh-remote-wire';
|
|
21
|
-
export class SystemSleepBackend {
|
|
22
|
-
child;
|
|
23
|
-
lastError;
|
|
24
|
-
/** 平台名是构造时定下的,不与接口方法 `platform()` 同名。 */
|
|
25
|
-
osName;
|
|
26
|
-
constructor(platform = process.platform) {
|
|
27
|
-
this.osName = platform;
|
|
28
|
-
}
|
|
29
|
-
backend() {
|
|
30
|
-
return detectBackend(this.osName);
|
|
31
|
-
}
|
|
32
|
-
platform() {
|
|
33
|
-
return this.osName;
|
|
34
|
-
}
|
|
35
|
-
isActive() {
|
|
36
|
-
return this.child !== undefined;
|
|
37
|
-
}
|
|
38
|
-
start(ownerPid, keepDisplay) {
|
|
39
|
-
if (!isSleepSupported(this.osName)) {
|
|
40
|
-
const message = `${this.osName} 没有受支持的防休眠后端`;
|
|
41
|
-
this.lastError = message;
|
|
42
|
-
return { ok: false, message };
|
|
43
|
-
}
|
|
44
|
-
if (this.child)
|
|
45
|
-
return { ok: true };
|
|
46
|
-
const command = buildSleepCommand(this.osName, ownerPid, keepDisplay);
|
|
47
|
-
if (!command) {
|
|
48
|
-
const message = '防休眠命令构造失败';
|
|
49
|
-
this.lastError = message;
|
|
50
|
-
return { ok: false, message };
|
|
51
|
-
}
|
|
52
|
-
try {
|
|
53
|
-
const child = spawn(command.command, command.args, { stdio: 'ignore' });
|
|
54
|
-
child.on('error', (error) => {
|
|
55
|
-
this.lastError = String(error?.message ?? error);
|
|
56
|
-
this.child = undefined;
|
|
57
|
-
});
|
|
58
|
-
child.on('exit', (code) => {
|
|
59
|
-
if (code !== 0 && code !== null)
|
|
60
|
-
this.lastError = `${command.command} 退出码 ${code}`;
|
|
61
|
-
if (this.child === child)
|
|
62
|
-
this.child = undefined;
|
|
63
|
-
});
|
|
64
|
-
child.unref();
|
|
65
|
-
this.child = child;
|
|
66
|
-
this.lastError = undefined;
|
|
67
|
-
return { ok: true };
|
|
68
|
-
}
|
|
69
|
-
catch (error) {
|
|
70
|
-
const message = String(error?.message ?? error);
|
|
71
|
-
this.lastError = message;
|
|
72
|
-
return { ok: false, message };
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
stop() {
|
|
76
|
-
const child = this.child;
|
|
77
|
-
this.child = undefined;
|
|
78
|
-
if (!child)
|
|
79
|
-
return;
|
|
80
|
-
try {
|
|
81
|
-
child.kill('SIGTERM');
|
|
82
|
-
}
|
|
83
|
-
catch {
|
|
84
|
-
/* 已经退了 */
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
get error() {
|
|
88
|
-
return this.lastError;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
//# sourceMappingURL=sleep-posix.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sleep-posix.js","sourceRoot":"","sources":["../../../src/platform/sleep-posix.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,246 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ports — 插件的端口定义(内核/传输/防休眠/时钟/存储)。
|
|
3
|
-
*
|
|
4
|
-
* 这一层是整个插件的"可测性契约":**只有 `platform/` 与 `shell/` 允许 import cordis
|
|
5
|
-
* 与 `@deepseek-ai/*`**,`core/` 只认这里的形状。旧实现做不到这一点——它的
|
|
6
|
-
* 36 项测试全靠手写 cordis 替身,因为内核调用与业务逻辑写在同一个对象里。
|
|
7
|
-
*
|
|
8
|
-
* 三条设计约束:
|
|
9
|
-
*
|
|
10
|
-
* 1. **内核面必须能被"部分实现"**。真实宿主在不同代际暴露的能力不一样
|
|
11
|
-
* (列会话有两条路、审批有 waterfall、提问是单提供者服务),所以可选方法
|
|
12
|
-
* 用 `?:` 表达,调用方负责探测与降级——不是用一个 `capabilities` 位图,
|
|
13
|
-
* 那会退化成"猜平台有什么"。
|
|
14
|
-
* 2. **审批与提问走"参与者"语义,不是观测**。`respondApproval` / `ask` 返回 Promise
|
|
15
|
-
* 并由调用方(`core/runtime`)挂到手机上;平台侧的 `approval/request` 是 waterfall,
|
|
16
|
-
* 返回 outcome 即声明"这个决定我认领了",不调 `next()` 就不会轮到桌面 UI。
|
|
17
|
-
* 3. **所有返回给 core 的形状都是插件自己的类型**(`KernelSession`、`PendingApproval`…),
|
|
18
|
-
* 平台对象一律在适配器里折叠完再出来。这样协议层的 `SessionSummary` 与内核
|
|
19
|
-
* 代际变化之间有一层可测的翻译,而不是满屏 `as any`。
|
|
20
|
-
*/
|
|
21
|
-
import type { QuestionItem, SessionSummary } from 'dsh-remote-wire';
|
|
22
|
-
/** 插件端口只需要四个方法形状的 socket,方便用内存替身测试。 */
|
|
23
|
-
export interface PeerSink {
|
|
24
|
-
/** 向某个会话的所有在线客户端发一条已加密载荷;返回是否有活客户端。 */
|
|
25
|
-
broadcast(payload: unknown): boolean;
|
|
26
|
-
/** 单播到某个客户端(用于只回给发起者)。 */
|
|
27
|
-
toClient(clientId: string, payload: unknown): boolean;
|
|
28
|
-
}
|
|
29
|
-
/** 内核报告的一条会话在插件内部的形状(还没变成线格式)。 */
|
|
30
|
-
export interface KernelSession {
|
|
31
|
-
summary: SessionSummary;
|
|
32
|
-
/** 该会话此刻是否有活的 agent 在跑(决定要不要持锁)。 */
|
|
33
|
-
live: boolean;
|
|
34
|
-
/** 列表来自哪条路(持久化语料 / 仅本进程活会话);"只报一个会话"是不是故障,看这个字段。 */
|
|
35
|
-
listingSource?: 'sessionQuery' | 'sessions';
|
|
36
|
-
}
|
|
37
|
-
/** 会话的一次事件,已经翻译成插件词汇。 */
|
|
38
|
-
export type KernelEvent = {
|
|
39
|
-
kind: 'delta';
|
|
40
|
-
sessionId: string;
|
|
41
|
-
messageId: string;
|
|
42
|
-
text: string;
|
|
43
|
-
done: boolean;
|
|
44
|
-
role?: 'assistant' | 'user' | 'system';
|
|
45
|
-
} | {
|
|
46
|
-
kind: 'tool';
|
|
47
|
-
sessionId: string;
|
|
48
|
-
callId: string;
|
|
49
|
-
phase: 'started' | 'args' | 'completed' | 'failed';
|
|
50
|
-
tool?: string;
|
|
51
|
-
title?: string;
|
|
52
|
-
argsPreview?: string;
|
|
53
|
-
resultPreview?: string;
|
|
54
|
-
} | {
|
|
55
|
-
kind: 'run-state';
|
|
56
|
-
sessionId: string;
|
|
57
|
-
state: 'running' | 'idle';
|
|
58
|
-
detail?: string;
|
|
59
|
-
} | {
|
|
60
|
-
kind: 'title';
|
|
61
|
-
sessionId: string;
|
|
62
|
-
title: string;
|
|
63
|
-
} | {
|
|
64
|
-
kind: 'sessions-changed';
|
|
65
|
-
reason?: string;
|
|
66
|
-
};
|
|
67
|
-
/**
|
|
68
|
-
* 一页历史。
|
|
69
|
-
*
|
|
70
|
-
* `events` 用的是**与实时流同一套 KernelEvent 词汇**,而不是另立一套"历史消息"形状:
|
|
71
|
-
* 内核日志里的事件和实时 `session/event` 本来就是同一种东西(都是
|
|
72
|
-
* `{type, seq, data}`),所以翻译函数可以原样复用,出站构造器也可以原样复用。
|
|
73
|
-
* 另立一套的话,同一段翻译逻辑要写两遍,而两份实现分叉的表现是
|
|
74
|
-
* "实时看着对、历史看着怪"——靠肉眼很难发现。
|
|
75
|
-
*
|
|
76
|
-
* `nextBeforeSeq` 省略 = 这是最初的一页(没有更早的内容了)。
|
|
77
|
-
*/
|
|
78
|
-
export interface KernelHistoryPage {
|
|
79
|
-
events: KernelEvent[];
|
|
80
|
-
nextBeforeSeq?: number;
|
|
81
|
-
}
|
|
82
|
-
/** 一次待决审批。`id` 是插件自己生成的关联键(手机回传时逐字带回)。 */
|
|
83
|
-
export interface PendingApproval {
|
|
84
|
-
id: string;
|
|
85
|
-
sessionId: string;
|
|
86
|
-
/** 平台侧的审计 id(`approval/asked` 里那个),有就带着,便于取证。 */
|
|
87
|
-
platformId?: string;
|
|
88
|
-
action: string;
|
|
89
|
-
reason?: string;
|
|
90
|
-
/** 挂起的 abort 信号:手机一直不回答案时由平台侧撤销。 */
|
|
91
|
-
signal?: AbortSignal;
|
|
92
|
-
/** 认领这次决定:返回平台词汇的 outcome。 */
|
|
93
|
-
settle(outcome: ApprovalOutcomeValue): void;
|
|
94
|
-
}
|
|
95
|
-
/** 平台词汇(`@deepseek-ai/dsh-user-approval` 的 `ApprovalOutcome`)。 */
|
|
96
|
-
export type ApprovalOutcomeValue = 'allowed-once' | 'rejected' | 'cancelled' | 'unavailable';
|
|
97
|
-
/** 一次待答提问。选项用 label 与平台交换,`id` 只在插件与手机之间使用。 */
|
|
98
|
-
export interface PendingQuestion {
|
|
99
|
-
id: string;
|
|
100
|
-
sessionId: string;
|
|
101
|
-
questions: QuestionItem[];
|
|
102
|
-
settle(answer: AskUserQuestionAnswerValue): void;
|
|
103
|
-
cancel(): void;
|
|
104
|
-
}
|
|
105
|
-
/** 平台侧的答案形状(`selected` 装的是**选项 label**,不是我们的 id)。 */
|
|
106
|
-
export interface AskUserQuestionAnswerValue {
|
|
107
|
-
answers: Array<{
|
|
108
|
-
id: string;
|
|
109
|
-
selected: string[];
|
|
110
|
-
custom?: string;
|
|
111
|
-
}>;
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* 内核端口。`listSessions` / `sendPrompt` / `interrupt` 是手机三大动作的落点,
|
|
115
|
-
* 其余是可选能力面:宿主代际不同就有不同,缺失时调用方必须能报出"缺哪个成员 +
|
|
116
|
-
* 该服务对象实际有哪些 key",而不是静默换一个载体。
|
|
117
|
-
*/
|
|
118
|
-
/** core 提供给内核适配器的人工交互入口。 */
|
|
119
|
-
export interface InteractionSink {
|
|
120
|
-
/** 一次审批请求。返回 `'decline'` 让适配器去调平台的 `next()`。 */
|
|
121
|
-
approval(info: {
|
|
122
|
-
sessionId: string;
|
|
123
|
-
action: string;
|
|
124
|
-
reason?: string;
|
|
125
|
-
signal?: AbortSignal;
|
|
126
|
-
}): Promise<ApprovalDecision>;
|
|
127
|
-
/** 一次提问请求。返回 null 表示无人应答(适配器须转成明确失败,不许静默挂住 agent)。 */
|
|
128
|
-
question(info: {
|
|
129
|
-
sessionId: string;
|
|
130
|
-
questions: QuestionItem[];
|
|
131
|
-
signal?: AbortSignal;
|
|
132
|
-
}): Promise<AskUserQuestionAnswerValue | null>;
|
|
133
|
-
}
|
|
134
|
-
/** 审批结论,外加一个"我不认领"。 */
|
|
135
|
-
export type ApprovalDecision = ApprovalOutcomeValue | 'decline';
|
|
136
|
-
export interface KernelPort {
|
|
137
|
-
/** 这条载体的名字,会进 status.json(`services` / `apiproxy` / `mock`)。 */
|
|
138
|
-
readonly carrier: string;
|
|
139
|
-
listSessions(limit: number): Promise<KernelSession[]>;
|
|
140
|
-
runState(sessionId: string): Promise<{
|
|
141
|
-
running: boolean;
|
|
142
|
-
state: SessionSummary['state'];
|
|
143
|
-
}>;
|
|
144
|
-
sendPrompt(sessionId: string, text: string): Promise<{
|
|
145
|
-
ok: boolean;
|
|
146
|
-
message?: string;
|
|
147
|
-
}>;
|
|
148
|
-
interrupt(sessionId: string): Promise<{
|
|
149
|
-
ok: boolean;
|
|
150
|
-
message?: string;
|
|
151
|
-
}>;
|
|
152
|
-
/**
|
|
153
|
-
* 读一条会话已有的历史(手机打开会话时用)。
|
|
154
|
-
*
|
|
155
|
-
* **可选**:读历史依赖宿主暴露 `sessionQuery`(`listSessions` / `readTitleSnapshots`
|
|
156
|
-
* 那条路线的同一个服务),而不同代际的能力面不一样。缺失时调用方必须能明确报出
|
|
157
|
-
* "这一代没有这个能力",而不是回一个空列表——空列表在手机上就是"这个会话没内容",
|
|
158
|
-
* 那是一个会让人查错方向的假事实。
|
|
159
|
-
*
|
|
160
|
-
* `options.beforeSeq` 是上一页给的游标(取 `seq < beforeSeq`);省略表示要最新一页。
|
|
161
|
-
*/
|
|
162
|
-
readHistory?(sessionId: string, options: {
|
|
163
|
-
beforeSeq?: number;
|
|
164
|
-
limit: number;
|
|
165
|
-
}): Promise<KernelHistoryPage>;
|
|
166
|
-
/**
|
|
167
|
-
* 新建一条会话(手机上那个「新建会话」)。
|
|
168
|
-
*
|
|
169
|
-
* **可选**:它依赖宿主暴露 `sessionController`,而不同代际暴露的服务面不一样。
|
|
170
|
-
* 缺失时调用方必须明确拒绝并说出缺哪一层,**不许**回一条"已创建"——
|
|
171
|
-
* 手机拿着一个假的 sessionId 一路走下去,失败点会离病根很远。
|
|
172
|
-
*
|
|
173
|
-
* 成功时返回**主机分配**的 id。刻意不接受标题:命名是主机那一侧的事
|
|
174
|
-
* (创建时不传 sessionId 由内核分配,不传 cwd 就用默认项目目录)。
|
|
175
|
-
*/
|
|
176
|
-
newSession?(): Promise<{
|
|
177
|
-
ok: boolean;
|
|
178
|
-
sessionId?: string;
|
|
179
|
-
message?: string;
|
|
180
|
-
}>;
|
|
181
|
-
/** 订阅会话事件;返回退订函数。实现必须拒绝订阅 waterfall(见 guard.ts)。 */
|
|
182
|
-
subscribe(onEvent: (event: KernelEvent) => void): () => void;
|
|
183
|
-
/**
|
|
184
|
-
* 登记"谁来处理一次人工交互"。
|
|
185
|
-
*
|
|
186
|
-
* 方向很重要:**交互由平台发起**(审批是 `approval/request` waterfall 的参与者、
|
|
187
|
-
* 提问是 `ctx.userQuestions` 的提供者),适配器只负责把它转交给 core,
|
|
188
|
-
* 并在 core 给出结论后把结论送回平台。所以这里是 sink 注册,不是 `ask()` 调用。
|
|
189
|
-
*
|
|
190
|
-
* core 返回 `'decline'` 表示"这局我不认领"(例如此刻没有已配对的手机在线),
|
|
191
|
-
* 审批适配器此时**必须**调用平台的 `next()` 把决定权交还桌面 UI;
|
|
192
|
-
* 提问服务是单提供者、没有 next 可交还,因此 decline 一律转成明确失败,
|
|
193
|
-
* 绝不静默挂住 agent(取证:dsh-user-questions 只允许一个活跃 provider)。
|
|
194
|
-
*/
|
|
195
|
-
attachInteractionSink?(sink: InteractionSink): () => void;
|
|
196
|
-
/** 冷会话续跑(归档/未加载的会话发指令前需要)。 */
|
|
197
|
-
ensureRunnable?(sessionId: string): Promise<{
|
|
198
|
-
ok: boolean;
|
|
199
|
-
message?: string;
|
|
200
|
-
}>;
|
|
201
|
-
/**
|
|
202
|
-
* 一条会话的工作区目录(会话头里的 `cwd`)。
|
|
203
|
-
*
|
|
204
|
-
* **可选**:宿主代际不同,能拿到 `cwd` 的面也不同。只查**活会话**(`sessions.get(id)`,
|
|
205
|
-
* 同步、零成本)——用到它的两个调用点(`/drc pair` 与右栏那条路由)都发生在用户正在
|
|
206
|
-
* 那条会话里操作的时刻,活会话这条足以覆盖;查不到就返回 undefined,调用方退回
|
|
207
|
-
* `~/.dsh/` 并在卡片上如实显示那个路径。
|
|
208
|
-
*
|
|
209
|
-
* 返回值必须是绝对路径(会话头里的 `cwd` 被内核校验为绝对路径),调用方直接当目录用。
|
|
210
|
-
*/
|
|
211
|
-
sessionWorkspace?(sessionId: string): string | undefined;
|
|
212
|
-
/** 当前模型选择,仅用于展示与"没模型就拒绝"的前置判断。 */
|
|
213
|
-
modelSelection?(): {
|
|
214
|
-
provider: string;
|
|
215
|
-
model: string;
|
|
216
|
-
} | undefined;
|
|
217
|
-
/** 诊断:内核服务实际暴露了哪些成员,出错时打出来。 */
|
|
218
|
-
describe(): Record<string, string | number | boolean>;
|
|
219
|
-
}
|
|
220
|
-
/** 传输端口:core 通过它发消息,不关心 socket。 */
|
|
221
|
-
export interface TransportPort {
|
|
222
|
-
/** 有没有能收这条会话消息的对端(决定审批要不要自己认领)。 */
|
|
223
|
-
hasPeer(sessionId: string): boolean;
|
|
224
|
-
broadcast(payload: unknown, sessionId?: string): void;
|
|
225
|
-
}
|
|
226
|
-
/** 防休眠后端端口。 */
|
|
227
|
-
export interface SleepPort {
|
|
228
|
-
backend(): string;
|
|
229
|
-
platform(): string;
|
|
230
|
-
start(ownerPid: number, keepDisplay: boolean): {
|
|
231
|
-
ok: boolean;
|
|
232
|
-
message?: string;
|
|
233
|
-
};
|
|
234
|
-
stop(): void;
|
|
235
|
-
isActive(): boolean;
|
|
236
|
-
}
|
|
237
|
-
/** 时间与随机性注入点:窗口化与退避策略因此可以确定性测试。 */
|
|
238
|
-
export interface Clock {
|
|
239
|
-
now(): number;
|
|
240
|
-
setTimeout(fn: () => void, ms: number): unknown;
|
|
241
|
-
clearTimeout(handle: unknown): void;
|
|
242
|
-
}
|
|
243
|
-
/** 状态快照落盘(GUI 宿主没人看 stdout,这个文件是排错第一入口)。 */
|
|
244
|
-
export interface StatusSink {
|
|
245
|
-
write(snapshot: Record<string, unknown>): void;
|
|
246
|
-
}
|
package/dist/src/ports/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/ports/index.ts"],"names":[],"mappings":""}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
export interface PluginConfig {
|
|
2
|
-
enabled: boolean;
|
|
3
|
-
serverUrl: string;
|
|
4
|
-
hostToken: string;
|
|
5
|
-
/** 指向真正的 token 所在的环境变量名(token 本身不进 patch 文件也可以)。 */
|
|
6
|
-
hostTokenEnv: string;
|
|
7
|
-
hostId: string;
|
|
8
|
-
hostLabel: string;
|
|
9
|
-
keepAwake: {
|
|
10
|
-
enabled: boolean;
|
|
11
|
-
idleReleaseSec: number;
|
|
12
|
-
keepDisplay: boolean;
|
|
13
|
-
};
|
|
14
|
-
mockBridge: boolean;
|
|
15
|
-
statusFile: string;
|
|
16
|
-
unarchiveOnPrompt: boolean;
|
|
17
|
-
/** 启动后自动发布一张配对码并把 QR 写进 status.json(验证辅助,默认关)。 */
|
|
18
|
-
pairOnStartSec: number;
|
|
19
|
-
/** 向中继申请 PSK 有效期;服务端权威值会覆盖它(见 transport/relay.ts)。 */
|
|
20
|
-
pairTtlMs: number;
|
|
21
|
-
/** 是否把配对二维码写成 PNG(默认**开**:文本二维码在 DSH 命令卡里扫不出来,见下方默认值注释)。 */
|
|
22
|
-
qrImage: boolean;
|
|
23
|
-
qrOpen: boolean;
|
|
24
|
-
/** 是否给文本二维码套 ANSI 反色。默认关:宿主按纯文本渲染时会把转义序列打成乱码。 */
|
|
25
|
-
qrAnsi: boolean;
|
|
26
|
-
qrStyle: 'ascii' | 'block' | 'half';
|
|
27
|
-
/** 强 carrier 未到时,等多久才落到弱 carrier。 */
|
|
28
|
-
carrierGraceMs: number;
|
|
29
|
-
/** 提问接管:会剥夺桌面 UI 的提问能力,所以默认关(见 core/runtime.ts)。 */
|
|
30
|
-
takeOverQuestions: boolean;
|
|
31
|
-
approvalTimeoutSec: number;
|
|
32
|
-
listingRefreshSec: number;
|
|
33
|
-
/**
|
|
34
|
-
* 一条配对通道多久没有任何收发就可以被剪掉(秒)。
|
|
35
|
-
*
|
|
36
|
-
* 为什么需要:D3 之后配对通道跨断连长存,而**中继侧的空闲 TTL 是 7 天**
|
|
37
|
-
* (`DRC_CONV_IDLE_TTL_MS`),"中继先忘掉这条会话"几乎不会发生。不剪的话,
|
|
38
|
-
* 每天配一次对的主机两周就能攒两百多条密钥,且每次广播都对它们逐个密封一遍。
|
|
39
|
-
* 剪枝一定同时发 `session-leave`,所以手机不会因此静默转圈——它撞上的是
|
|
40
|
-
* 中文的"会话已失效,请重新配对"。
|
|
41
|
-
*/
|
|
42
|
-
conversationIdleTtlSec: number;
|
|
43
|
-
}
|
|
44
|
-
export declare const DEFAULT_CONFIG: PluginConfig;
|
|
45
|
-
export interface ConfigProblem {
|
|
46
|
-
level: 'error' | 'warn';
|
|
47
|
-
field: string;
|
|
48
|
-
message: string;
|
|
49
|
-
}
|
|
50
|
-
/** 合成三级配置。`injected` 来自 cordis 的 patch 层。 */
|
|
51
|
-
export declare function readConfig(injected: Partial<PluginConfig> | undefined, env?: NodeJS.ProcessEnv): PluginConfig;
|
|
52
|
-
/** 校验 + 就地夹取。error 级问题会让上层拒绝启动 runtime(但仍留 status 面包屑)。 */
|
|
53
|
-
export declare function validateConfig(config: PluginConfig): ConfigProblem[];
|
|
54
|
-
/** 令牌脱敏:日志与 status.json 里都只允许出现这个形态。 */
|
|
55
|
-
export declare function redactSecret(value: string): string;
|
|
56
|
-
export { redactSecret as redact };
|