@yfwu2020/dsh-selection-explain 0.13.0 → 0.14.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/README.md +3 -3
- package/lib/client.js +11899 -11398
- package/lib/client.js.map +4 -4
- package/lib/host/analyze-conclusion.js +115 -0
- package/lib/host/analyze-conclusion.js.map +1 -0
- package/lib/host/analyze-execution-types.js +2 -0
- package/lib/host/analyze-execution-types.js.map +1 -0
- package/lib/host/analyze-execution.js +166 -0
- package/lib/host/analyze-execution.js.map +1 -0
- package/lib/host/analyze-history.js +110 -0
- package/lib/host/analyze-history.js.map +1 -0
- package/lib/host/analyze-messages.js +95 -0
- package/lib/host/analyze-messages.js.map +1 -0
- package/lib/host/analyze-output.js +69 -0
- package/lib/host/analyze-output.js.map +1 -0
- package/lib/host/analyze-prompt.js +110 -0
- package/lib/host/analyze-prompt.js.map +1 -0
- package/lib/host/analyze-request.js +129 -0
- package/lib/host/analyze-request.js.map +1 -0
- package/lib/host/analyze-round.js +121 -0
- package/lib/host/analyze-round.js.map +1 -0
- package/lib/host/analyze-tool-execution.js +98 -0
- package/lib/host/analyze-tool-execution.js.map +1 -0
- package/lib/host/analyze-tools.js +79 -0
- package/lib/host/analyze-tools.js.map +1 -0
- package/lib/host/analyze-types.js +2 -0
- package/lib/host/analyze-types.js.map +1 -0
- package/lib/host/analyze.js +30 -977
- package/lib/host/analyze.js.map +1 -1
- package/lib/host/native-probe.js +66 -0
- package/lib/host/native-probe.js.map +1 -0
- package/lib/host/plugin.js +9 -10
- package/lib/host/plugin.js.map +1 -1
- package/lib/host/promote-seed.js +111 -0
- package/lib/host/promote-seed.js.map +1 -0
- package/lib/host/promote.js +53 -153
- package/lib/host/promote.js.map +1 -1
- package/lib/host/shot-capture.js +322 -0
- package/lib/host/shot-capture.js.map +1 -0
- package/lib/host/shot-geometry.js +183 -0
- package/lib/host/shot-geometry.js.map +1 -0
- package/lib/host/shot-platform.js +208 -0
- package/lib/host/shot-platform.js.map +1 -0
- package/lib/host/shot-service.js +127 -0
- package/lib/host/shot-service.js.map +1 -0
- package/lib/host/shot-types.js +5 -0
- package/lib/host/shot-types.js.map +1 -0
- package/lib/host/shot.js +117 -949
- package/lib/host/shot.js.map +1 -1
- package/lib/types/host/analyze-conclusion.d.ts +3 -0
- package/lib/types/host/analyze-execution-types.d.ts +54 -0
- package/lib/types/host/analyze-execution.d.ts +3 -0
- package/lib/types/host/analyze-history.d.ts +41 -0
- package/lib/types/host/analyze-messages.d.ts +15 -0
- package/lib/types/host/analyze-output.d.ts +8 -0
- package/lib/types/host/analyze-prompt.d.ts +15 -0
- package/lib/types/host/analyze-request.d.ts +28 -0
- package/lib/types/host/analyze-round.d.ts +7 -0
- package/lib/types/host/analyze-tool-execution.d.ts +4 -0
- package/lib/types/host/analyze-tools.d.ts +15 -0
- package/lib/types/host/analyze-types.d.ts +13 -0
- package/lib/types/host/analyze.d.ts +4 -4
- package/lib/types/host/native-probe.d.ts +10 -0
- package/lib/types/host/promote-seed.d.ts +24 -0
- package/lib/types/host/shot-capture.d.ts +11 -0
- package/lib/types/host/shot-geometry.d.ts +37 -0
- package/lib/types/host/shot-platform.d.ts +11 -0
- package/lib/types/host/shot-service.d.ts +17 -0
- package/lib/types/host/shot-types.d.ts +105 -0
- package/lib/types/host/shot.d.ts +14 -71
- package/native/window-list.c +139 -0
- package/package.json +2 -1
package/lib/types/host/shot.d.ts
CHANGED
|
@@ -1,73 +1,16 @@
|
|
|
1
|
+
/** Screenshot HTTP boundary. Each plugin application owns one service and its disposal. */
|
|
1
2
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
-
import type {
|
|
3
|
-
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
export interface ShotPending {
|
|
16
|
-
id: string;
|
|
17
|
-
at: number;
|
|
18
|
-
/** 这次用的取景范围 / 触发模式(客户端据此决定画不画框、走卡片还是附件)。 */
|
|
19
|
-
scope: ShotScope;
|
|
20
|
-
mode: ShotMode;
|
|
21
|
-
/** 图里要不要画红框(选区之外还有内容时为 true;仅选区恒为 false)。 */
|
|
22
|
-
frame: boolean;
|
|
23
|
-
/** 最终图的文件名(落在临时目录,按 shot 序号独立命名)。 */
|
|
24
|
-
imagePath: string;
|
|
25
|
-
/** 选区在**这张图里**的位置(像素坐标,可以直接拿去画框)。 */
|
|
26
|
-
rect: ShotRect;
|
|
27
|
-
/** 截图覆盖的范围(点):整窗 / 外扩后的选区 / 整屏;仅选区时就是选区本身。 */
|
|
28
|
-
windowRect: ShotRect;
|
|
29
|
-
/** 选区在屏幕上的位置(点)。 */
|
|
30
|
-
selectionRect: ShotRect;
|
|
31
|
-
/** 截图像素与点的比例(Retina 一般是 2)。 */
|
|
32
|
-
scale: number;
|
|
33
|
-
/** 窗口截图四周的留白(像素)—— `screencapture -l` 会连窗口阴影一起截进来,
|
|
34
|
-
* 内容不是从 (0,0) 开始的,必须把这段留白算进红框位置。 */
|
|
35
|
-
pad: {
|
|
36
|
-
x: number;
|
|
37
|
-
y: number;
|
|
38
|
-
};
|
|
39
|
-
/** 所属窗口的名字(调试用)。 */
|
|
40
|
-
owner: string;
|
|
41
|
-
/** 整窗截图是否已经做好(`/shot/image` 会等它;客户端拿到事件就能先画框)。 */
|
|
42
|
-
ready: boolean;
|
|
43
|
-
}
|
|
44
|
-
/** 一次截图失败(客户端通过长轮询取走,用来给用户一句人话)。 */
|
|
45
|
-
export interface ShotError {
|
|
46
|
-
code: string;
|
|
47
|
-
message: string;
|
|
48
|
-
at: number;
|
|
49
|
-
}
|
|
50
|
-
/** 平台是否受支持(目前只做 macOS:整窗截图与矩形都依赖它)。 */
|
|
51
|
-
export declare function shotSupported(): boolean;
|
|
52
|
-
/** `POST /api/shot/start` —— 开始一次截图(可带 `?rect=x,y,w,h&scope=…` 供测试)。 */
|
|
53
|
-
export declare function handleShotStart(req: IncomingMessage, res: ServerResponse, config?: Pick<Config, 'shotCardScope' | 'shotPanelScope' | 'shotMargin'>): Promise<void>;
|
|
54
|
-
/** `GET /api/shot/pending` —— 长轮询,等下一次截图结果或失败原因(最多 25 秒)。 */
|
|
55
|
-
export declare function handleShotPending(_req: IncomingMessage, res: ServerResponse): void;
|
|
56
|
-
/** `GET /api/shot/image?id=` —— 把图按字节回给客户端(不进 JSON,避免几 MB 的 base64)。 */
|
|
57
|
-
export declare function handleShotImage(req: IncomingMessage, res: ServerResponse): Promise<void>;
|
|
58
|
-
/** 客户端加载时回报的自检结果(开发期用,只存内存)。 */
|
|
59
|
-
export declare let clientHello: unknown;
|
|
60
|
-
/** 按 stage 保留最近一次上报:'geometry' 这种关键诊断不会被后面的 'uploaded' 覆盖。 */
|
|
61
|
-
export declare const clientReports: Record<string, unknown>;
|
|
62
|
-
export declare function handleShotHello(req: IncomingMessage, res: ServerResponse): void;
|
|
63
|
-
export declare function shotStatus(): {
|
|
64
|
-
available: boolean;
|
|
65
|
-
reason: string;
|
|
66
|
-
capturing: boolean;
|
|
67
|
-
total: number;
|
|
68
|
-
lastError: string;
|
|
3
|
+
import type { ShotConfig, ShotPlatform } from './shot-types.js';
|
|
4
|
+
export type { ShotScope, ShotMode, ShotRect, ShotPending, ShotError } from './shot-types.js';
|
|
5
|
+
export { resolveWindowProbe, shotSupported } from './shot-platform.js';
|
|
6
|
+
export declare function createShotService(config?: ShotConfig, dependencies?: {
|
|
7
|
+
platform?: ShotPlatform;
|
|
8
|
+
}): {
|
|
9
|
+
handleShotStart: (req: IncomingMessage, res: ServerResponse) => Promise<void>;
|
|
10
|
+
handleShotPending: (req: IncomingMessage, res: ServerResponse) => void;
|
|
11
|
+
handleShotImage: (req: IncomingMessage, res: ServerResponse) => Promise<void>;
|
|
12
|
+
handleShotHello: (req: IncomingMessage, res: ServerResponse) => Promise<void>;
|
|
13
|
+
handleShotStatus: (_req: IncomingMessage, res: ServerResponse) => Promise<void>;
|
|
14
|
+
status: () => import("./shot-types.js").ShotStatus;
|
|
15
|
+
stop(): Promise<void>;
|
|
69
16
|
};
|
|
70
|
-
/** 插件卸载 / 热重载:把临时目录清掉(截图是临时的,没有留着的理由)。 */
|
|
71
|
-
export declare function stopShot(): Promise<void>;
|
|
72
|
-
/** `GET /api/shot/status` —— 调试/自检。 */
|
|
73
|
-
export declare function handleShotStatus(_req: IncomingMessage, res: ServerResponse): Promise<void>;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* dsh-selection-explain · 窗口列表探针(纯 C + CoreFoundation)
|
|
3
|
+
*
|
|
4
|
+
* 干什么:把"当前屏幕上所有窗口"的名字与矩形打成一个 JSON 数组。
|
|
5
|
+
* 为什么需要它:截图提问要"带出整窗" —— 用户框了一块,我们要知道**那块属于哪个窗口**,
|
|
6
|
+
* 才能把整个窗口截下来(而不是裁一圈边框)。Node 没有 CoreGraphics 绑定,所以编一个小二进制。
|
|
7
|
+
* 与本包 native/mic-probe.c 同一套办法:纯 C、无 ObjC、出错就整体降级。
|
|
8
|
+
*
|
|
9
|
+
* 输出(一行 JSON,数组顺序即前后顺序,前一个更靠前):
|
|
10
|
+
* [{"id":123,"x":0,"y":25,"w":1200,"h":800,"layer":0,"alpha":1.00,"owner":"Code"}, ...]
|
|
11
|
+
*
|
|
12
|
+
* 约定:
|
|
13
|
+
* · 只列 on-screen、非桌面元素的窗口;宽或高 < 8 的丢掉(菜单残片、零尺寸辅助窗口);
|
|
14
|
+
* · layer 0 是普通应用窗口(菜单栏/悬浮窗/状态栏都在别的层);
|
|
15
|
+
* · 坐标是**全局点**(左上角原点 = 主屏左上角),与截图文件里那个矩形同一套坐标系。
|
|
16
|
+
*
|
|
17
|
+
* 另有 `--displays`:打"当前活跃显示器"的矩形(全局点)与像素尺寸。
|
|
18
|
+
* 截图范围是「选区 + 留白」时,用它把外扩矩形裁到选区中心所在的那块屏,
|
|
19
|
+
* 否则 screencapture -R 越界时的裁切原点不可预期(红框会偏)。
|
|
20
|
+
* [{"id":1,"x":0,"y":0,"w":1920,"h":1080,"index":1,"main":1}, ...]
|
|
21
|
+
*
|
|
22
|
+
* `index` 是 `screencapture -D` 的编号(1 = 主显示器),按 CGGetActiveDisplayList
|
|
23
|
+
* 的顺序给;`-D` 是截副屏唯一可靠的办法(`-R` 不接受负坐标)。
|
|
24
|
+
* 截图的实际像素尺寸以 `screencapture` 输出为准,不再从这里报(不同缩放下
|
|
25
|
+
* CGDisplayPixelsWide 与截图像素并不等价)。
|
|
26
|
+
*/
|
|
27
|
+
#include <CoreGraphics/CoreGraphics.h>
|
|
28
|
+
#include <CoreFoundation/CoreFoundation.h>
|
|
29
|
+
#include <stdio.h>
|
|
30
|
+
#include <string.h>
|
|
31
|
+
|
|
32
|
+
/** JSON 字符串转义:owner 里可能出现引号/反斜杠(罕见,但别拼坏 JSON)。 */
|
|
33
|
+
static void jsonEscape(const char *src, char *dst, size_t n) {
|
|
34
|
+
size_t j = 0;
|
|
35
|
+
for (size_t i = 0; src && src[i] && j + 2 < n; i++) {
|
|
36
|
+
unsigned char c = (unsigned char)src[i];
|
|
37
|
+
if (c == '"' || c == '\\') {
|
|
38
|
+
dst[j++] = '\\';
|
|
39
|
+
dst[j++] = (char)c;
|
|
40
|
+
} else if (c < 0x20) {
|
|
41
|
+
dst[j++] = ' ';
|
|
42
|
+
} else {
|
|
43
|
+
dst[j++] = (char)c;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
dst[j] = '\0';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** CFNumber → double,失败给 fallback。 */
|
|
50
|
+
static double numOr(CFDictionaryRef dict, CFStringRef key, double fallback) {
|
|
51
|
+
CFTypeRef v = CFDictionaryGetValue(dict, key);
|
|
52
|
+
double out = fallback;
|
|
53
|
+
if (v && CFGetTypeID(v) == CFNumberGetTypeID()) {
|
|
54
|
+
if (!CFNumberGetValue((CFNumberRef)v, kCFNumberDoubleType, &out)) out = fallback;
|
|
55
|
+
}
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* `--displays`:活跃显示器的全局矩形(点)与像素尺寸。
|
|
61
|
+
*
|
|
62
|
+
* 坐标与 CGWindowList 的窗口矩形、截图的 xattr 矩形是同一套全局点坐标系;
|
|
63
|
+
* 副屏在主屏左边时 x 会是负数,调用方必须按**全局点**处理。
|
|
64
|
+
*/
|
|
65
|
+
static void printDisplays(void) {
|
|
66
|
+
CGDirectDisplayID ids[32];
|
|
67
|
+
uint32_t count = 0;
|
|
68
|
+
CGError err = CGGetActiveDisplayList(32, ids, &count);
|
|
69
|
+
/* 锁屏 / 显示器睡眠时 active 可能为空:退到 online,再退到主屏,不能因此让截图整体不可用 */
|
|
70
|
+
if (err != kCGErrorSuccess || count == 0) {
|
|
71
|
+
err = CGGetOnlineDisplayList(32, ids, &count);
|
|
72
|
+
}
|
|
73
|
+
if (err != kCGErrorSuccess || count == 0) {
|
|
74
|
+
ids[0] = CGMainDisplayID();
|
|
75
|
+
count = 1;
|
|
76
|
+
}
|
|
77
|
+
printf("[");
|
|
78
|
+
uint32_t emitted = 0;
|
|
79
|
+
for (uint32_t i = 0; i < count; i++) {
|
|
80
|
+
CGRect b = CGDisplayBounds(ids[i]);
|
|
81
|
+
if (b.size.width < 1 || b.size.height < 1) continue;
|
|
82
|
+
if (emitted > 0) printf(",");
|
|
83
|
+
printf("{\"id\":%u,\"x\":%.1f,\"y\":%.1f,\"w\":%.1f,\"h\":%.1f,\"index\":%u,\"main\":%d}",
|
|
84
|
+
(unsigned)ids[i], b.origin.x, b.origin.y, b.size.width, b.size.height,
|
|
85
|
+
emitted + 1, CGDisplayIsMain(ids[i]) ? 1 : 0);
|
|
86
|
+
emitted++;
|
|
87
|
+
}
|
|
88
|
+
printf("]\n");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
int main(int argc, char **argv) {
|
|
92
|
+
if (argc > 1 && strcmp(argv[1], "--displays") == 0) {
|
|
93
|
+
printDisplays();
|
|
94
|
+
return 0;
|
|
95
|
+
}
|
|
96
|
+
CFArrayRef wins = CGWindowListCopyWindowInfo(
|
|
97
|
+
kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements, kCGNullWindowID);
|
|
98
|
+
long n = wins ? CFArrayGetCount(wins) : 0;
|
|
99
|
+
printf("[");
|
|
100
|
+
int first = 1;
|
|
101
|
+
for (long i = 0; i < n; i++) {
|
|
102
|
+
CFDictionaryRef w = (CFDictionaryRef)CFArrayGetValueAtIndex(wins, i);
|
|
103
|
+
if (!w || CFGetTypeID(w) != CFDictionaryGetTypeID()) continue;
|
|
104
|
+
|
|
105
|
+
CFTypeRef idRef = CFDictionaryGetValue(w, kCGWindowNumber);
|
|
106
|
+
if (!idRef || CFGetTypeID(idRef) != CFNumberGetTypeID()) continue;
|
|
107
|
+
int wid = 0;
|
|
108
|
+
if (!CFNumberGetValue((CFNumberRef)idRef, kCFNumberIntType, &wid)) continue;
|
|
109
|
+
|
|
110
|
+
/* 窗口矩形:CGWindowBounds 就是一个表示 CGRect 的字典,交给它自己解 */
|
|
111
|
+
CGRect rect;
|
|
112
|
+
CFTypeRef boundsRef = CFDictionaryGetValue(w, kCGWindowBounds);
|
|
113
|
+
if (!boundsRef || CFGetTypeID(boundsRef) != CFDictionaryGetTypeID()) continue;
|
|
114
|
+
if (!CGRectMakeWithDictionaryRepresentation((CFDictionaryRef)boundsRef, &rect)) continue;
|
|
115
|
+
if (rect.size.width < 8 || rect.size.height < 8) continue;
|
|
116
|
+
|
|
117
|
+
double layer = numOr(w, kCGWindowLayer, 0);
|
|
118
|
+
double alpha = numOr(w, kCGWindowAlpha, 1);
|
|
119
|
+
|
|
120
|
+
char owner[256];
|
|
121
|
+
CFTypeRef ownerRef = CFDictionaryGetValue(w, kCGWindowOwnerName);
|
|
122
|
+
if (ownerRef && CFGetTypeID(ownerRef) == CFStringGetTypeID()) {
|
|
123
|
+
CFStringGetCString((CFStringRef)ownerRef, owner, sizeof(owner), kCFStringEncodingUTF8);
|
|
124
|
+
} else {
|
|
125
|
+
owner[0] = '\0';
|
|
126
|
+
}
|
|
127
|
+
char safe[512];
|
|
128
|
+
jsonEscape(owner, safe, sizeof(safe));
|
|
129
|
+
|
|
130
|
+
if (!first) printf(",");
|
|
131
|
+
first = 0;
|
|
132
|
+
printf("{\"id\":%d,\"x\":%.1f,\"y\":%.1f,\"w\":%.1f,\"h\":%.1f,\"layer\":%d,\"alpha\":%.2f,\"owner\":\"%s\"}",
|
|
133
|
+
wid, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height,
|
|
134
|
+
(int)layer, alpha, safe);
|
|
135
|
+
}
|
|
136
|
+
printf("]\n");
|
|
137
|
+
if (wins) CFRelease(wins);
|
|
138
|
+
return 0;
|
|
139
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yfwu2020/dsh-selection-explain",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "DSH 划词解读:选中文字浮出按钮,点击弹窗流式显示专业中英翻译 + 该文字在当前上下文中的含义详解",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"files": [
|
|
9
9
|
"lib",
|
|
10
10
|
"native/mic-probe.c",
|
|
11
|
+
"native/window-list.c",
|
|
11
12
|
"cordis.patch.yml",
|
|
12
13
|
"skills",
|
|
13
14
|
"README.md",
|