@ai-agent-forge/plugin-desktop-windows-observe 0.85.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 +40 -0
- package/agent-forge.json +15 -0
- package/dist/capability.d.ts +13 -0
- package/dist/capability.d.ts.map +1 -0
- package/dist/capability.js +97 -0
- package/dist/capability.js.map +1 -0
- package/dist/entry.d.ts +14 -0
- package/dist/entry.d.ts.map +1 -0
- package/dist/entry.js +15 -0
- package/dist/entry.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/projection.d.ts +113 -0
- package/dist/projection.d.ts.map +1 -0
- package/dist/projection.js +226 -0
- package/dist/projection.js.map +1 -0
- package/dist/shared.d.ts +15 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +30 -0
- package/dist/shared.js.map +1 -0
- package/dist/types.d.ts +202 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +21 -0
- package/dist/types.js.map +1 -0
- package/dist/windows-uia-adapter.d.ts +68 -0
- package/dist/windows-uia-adapter.d.ts.map +1 -0
- package/dist/windows-uia-adapter.js +711 -0
- package/dist/windows-uia-adapter.js.map +1 -0
- package/package.json +57 -0
- package/plugin.json +12 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
const DESKTOP_MAX_WINDOWS_V1 = 64;
|
|
2
|
+
const DESKTOP_MAX_CONTROLS_V1 = 256;
|
|
3
|
+
export const DESKTOP_MAX_STRING_CHARS_V1 = 256;
|
|
4
|
+
const DESKTOP_MAX_RESULT_BYTES_V1 = 64 * 1024;
|
|
5
|
+
export const DESKTOP_MAX_POSTCONDITIONS_V1 = 32;
|
|
6
|
+
export const DESKTOP_MAX_TYPE_TEXT_CHARS_V1 = 4096;
|
|
7
|
+
export const DESKTOP_MAX_REPLAY_ACTIONS_V1 = 32;
|
|
8
|
+
const DESKTOP_CAPABILITY_IDS_V1 = [
|
|
9
|
+
"desktop-session",
|
|
10
|
+
"desktop-uia",
|
|
11
|
+
"desktop-input",
|
|
12
|
+
"desktop-vision",
|
|
13
|
+
"desktop-replay",
|
|
14
|
+
];
|
|
15
|
+
export function desktopFailure(operationId, code, message, status = "failed") {
|
|
16
|
+
return {
|
|
17
|
+
version: 1,
|
|
18
|
+
operationId,
|
|
19
|
+
status,
|
|
20
|
+
summary: message,
|
|
21
|
+
error: { version: 1, code, message },
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export function desktopBoundedString(value, label) {
|
|
25
|
+
if (typeof value !== "string" || value.length > DESKTOP_MAX_STRING_CHARS_V1)
|
|
26
|
+
throw new Error(`desktop-result-budget:${label}`);
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
/// 观察投影专用:显示文本超长时截断而非抛异常(dogfood 2026-09-25 实测,真实桌面
|
|
30
|
+
/// 单控件文本超上限很常见)。输入校验(type text/key/target)仍用 desktopBoundedString
|
|
31
|
+
/// 严格拒绝——截断输入等于静默打错字。
|
|
32
|
+
export function desktopClampedString(value, label) {
|
|
33
|
+
if (typeof value !== "string")
|
|
34
|
+
throw new Error(`desktop-result-budget:${label}`);
|
|
35
|
+
if (value.length > DESKTOP_MAX_STRING_CHARS_V1)
|
|
36
|
+
return value.slice(0, DESKTOP_MAX_STRING_CHARS_V1);
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
export function desktopRequiredString(value, label) {
|
|
40
|
+
const result = desktopBoundedString(value, label);
|
|
41
|
+
if (result.trim() === "")
|
|
42
|
+
throw new Error(`desktop-result-invalid:${label}`);
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
45
|
+
function desktopCapabilities(value) {
|
|
46
|
+
if (!Array.isArray(value))
|
|
47
|
+
return undefined;
|
|
48
|
+
const capabilities = value.filter((item) => typeof item === "string" && DESKTOP_CAPABILITY_IDS_V1.includes(item));
|
|
49
|
+
const unique = [...new Set(capabilities)].slice(0, DESKTOP_CAPABILITY_IDS_V1.length);
|
|
50
|
+
return unique.length === 0 ? undefined : unique;
|
|
51
|
+
}
|
|
52
|
+
function desktopBounds(value) {
|
|
53
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
54
|
+
throw new Error("desktop-result-invalid");
|
|
55
|
+
const record = value;
|
|
56
|
+
const bounds = { x: record.x, y: record.y, width: record.width, height: record.height };
|
|
57
|
+
if (Object.values(bounds).some((item) => typeof item !== "number" || !Number.isFinite(item)) ||
|
|
58
|
+
bounds.width < 0 ||
|
|
59
|
+
bounds.height < 0)
|
|
60
|
+
throw new Error("desktop-result-invalid");
|
|
61
|
+
return bounds;
|
|
62
|
+
}
|
|
63
|
+
function projectDesktopWindow(value) {
|
|
64
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
65
|
+
throw new Error("desktop-result-invalid");
|
|
66
|
+
const record = value;
|
|
67
|
+
if (record.version !== 1)
|
|
68
|
+
throw new Error("desktop-result-invalid");
|
|
69
|
+
return {
|
|
70
|
+
version: 1,
|
|
71
|
+
windowId: desktopClampedString(record.windowId, "windowId"),
|
|
72
|
+
appId: desktopClampedString(record.appId, "appId"),
|
|
73
|
+
title: desktopClampedString(record.title, "title"),
|
|
74
|
+
bounds: desktopBounds(record.bounds),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function projectDesktopControl(value) {
|
|
78
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
79
|
+
throw new Error("desktop-result-invalid");
|
|
80
|
+
const record = value;
|
|
81
|
+
if (record.version !== 1 || typeof record.enabled !== "boolean")
|
|
82
|
+
throw new Error("desktop-result-invalid");
|
|
83
|
+
return {
|
|
84
|
+
version: 1,
|
|
85
|
+
controlId: desktopClampedString(record.controlId, "controlId"),
|
|
86
|
+
windowId: desktopClampedString(record.windowId, "windowId"),
|
|
87
|
+
role: desktopClampedString(record.role, "role"),
|
|
88
|
+
name: desktopClampedString(record.name, "name"),
|
|
89
|
+
bounds: desktopBounds(record.bounds),
|
|
90
|
+
enabled: record.enabled,
|
|
91
|
+
...(record.value === undefined ? {} : { value: desktopClampedString(record.value, "value") }),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
export function projectDesktopObservation(value) {
|
|
95
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
96
|
+
throw new Error("desktop-result-invalid");
|
|
97
|
+
const record = value;
|
|
98
|
+
if (record.version !== 1 ||
|
|
99
|
+
typeof record.sessionId !== "string" ||
|
|
100
|
+
typeof record.observationId !== "string" ||
|
|
101
|
+
(record.source !== "mock" && record.source !== "windows-uia") ||
|
|
102
|
+
!Array.isArray(record.windows) ||
|
|
103
|
+
!Array.isArray(record.controls))
|
|
104
|
+
throw new Error("desktop-result-invalid");
|
|
105
|
+
const windows = record.windows.slice(0, DESKTOP_MAX_WINDOWS_V1).map(projectDesktopWindow);
|
|
106
|
+
const controls = record.controls.slice(0, DESKTOP_MAX_CONTROLS_V1).map(projectDesktopControl);
|
|
107
|
+
const observation = {
|
|
108
|
+
version: 1,
|
|
109
|
+
sessionId: desktopClampedString(record.sessionId, "sessionId"),
|
|
110
|
+
observationId: desktopClampedString(record.observationId, "observationId"),
|
|
111
|
+
source: record.source,
|
|
112
|
+
windows,
|
|
113
|
+
controls,
|
|
114
|
+
...(record.focusedControlId === undefined
|
|
115
|
+
? {}
|
|
116
|
+
: { focusedControlId: desktopClampedString(record.focusedControlId, "focusedControlId") }),
|
|
117
|
+
};
|
|
118
|
+
return {
|
|
119
|
+
observation,
|
|
120
|
+
truncated: {
|
|
121
|
+
windows: record.windows.length > DESKTOP_MAX_WINDOWS_V1,
|
|
122
|
+
controls: record.controls.length > DESKTOP_MAX_CONTROLS_V1,
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
export function desktopResultWithinBudget(value) {
|
|
127
|
+
if (new TextEncoder().encode(JSON.stringify(value)).byteLength > DESKTOP_MAX_RESULT_BYTES_V1)
|
|
128
|
+
throw new Error("desktop-result-budget");
|
|
129
|
+
return value;
|
|
130
|
+
}
|
|
131
|
+
function desktopObservationResult(value, operationId) {
|
|
132
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value) && "observationId" in value) {
|
|
133
|
+
const projected = projectDesktopObservation(value);
|
|
134
|
+
// 真实桌面控件数轻松超出 64KB 结果预算(dogfood 2026-09-25 实测):超预算时
|
|
135
|
+
// 控件/窗口逐级减半裁剪并如实标记 truncated,而不是让整次观察失败。
|
|
136
|
+
const controls = projected.observation.controls;
|
|
137
|
+
const windows = projected.observation.windows;
|
|
138
|
+
let controlCount = controls.length;
|
|
139
|
+
let windowCount = windows.length;
|
|
140
|
+
for (;;) {
|
|
141
|
+
try {
|
|
142
|
+
return desktopResultWithinBudget({
|
|
143
|
+
version: 1,
|
|
144
|
+
operationId,
|
|
145
|
+
status: "succeeded",
|
|
146
|
+
observation: {
|
|
147
|
+
...projected.observation,
|
|
148
|
+
controls: controls.slice(0, controlCount),
|
|
149
|
+
windows: windows.slice(0, windowCount),
|
|
150
|
+
},
|
|
151
|
+
truncated: {
|
|
152
|
+
windows: projected.truncated.windows || windowCount < windows.length,
|
|
153
|
+
controls: projected.truncated.controls || controlCount < controls.length,
|
|
154
|
+
},
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
if (controlCount > 0)
|
|
159
|
+
controlCount = Math.floor(controlCount / 2);
|
|
160
|
+
else if (windowCount > 0)
|
|
161
|
+
windowCount = Math.floor(windowCount / 2);
|
|
162
|
+
else
|
|
163
|
+
throw new Error("desktop-result-budget");
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value) && "status" in value) {
|
|
168
|
+
const status = value.status;
|
|
169
|
+
if (status === "unsupported" || status === "failed" || status === "cancelled" || status === "needs_user") {
|
|
170
|
+
const record0 = value;
|
|
171
|
+
const adapterError = "error" in record0 && record0.error !== null && typeof record0.error === "object"
|
|
172
|
+
? record0.error
|
|
173
|
+
: undefined;
|
|
174
|
+
const errorCode = adapterError && typeof adapterError.code === "string" ? adapterError.code : "desktop_adapter_failed";
|
|
175
|
+
const errorMessage = adapterError && typeof adapterError.message === "string"
|
|
176
|
+
? adapterError.message
|
|
177
|
+
: "Desktop observation is unavailable";
|
|
178
|
+
return desktopFailure(operationId, errorCode, errorMessage, status);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
throw new Error("desktop-result-invalid");
|
|
182
|
+
}
|
|
183
|
+
function desktopSessionResult(value, operationId) {
|
|
184
|
+
if (value === null || typeof value !== "object" || Array.isArray(value) || !("status" in value))
|
|
185
|
+
throw new Error("desktop-result-invalid");
|
|
186
|
+
const record = value;
|
|
187
|
+
if (record.status !== "succeeded" && record.status !== "unsupported" && record.status !== "failed")
|
|
188
|
+
throw new Error("desktop-result-invalid");
|
|
189
|
+
if (record.status !== "succeeded")
|
|
190
|
+
return desktopFailure(operationId, "desktop_adapter_unavailable", "Desktop session is unavailable", record.status);
|
|
191
|
+
const session = record.session;
|
|
192
|
+
if (session === null || typeof session !== "object" || Array.isArray(session))
|
|
193
|
+
throw new Error("desktop-result-invalid");
|
|
194
|
+
const item = session;
|
|
195
|
+
if (item.version !== 1 ||
|
|
196
|
+
typeof item.sessionId !== "string" ||
|
|
197
|
+
(item.isolation !== "foreground" && item.isolation !== "vm" && item.isolation !== "mock") ||
|
|
198
|
+
(item.status !== "ready" && item.status !== "unavailable" && item.status !== "stopped"))
|
|
199
|
+
throw new Error("desktop-result-invalid");
|
|
200
|
+
return desktopResultWithinBudget({
|
|
201
|
+
version: 1,
|
|
202
|
+
operationId,
|
|
203
|
+
status: "succeeded",
|
|
204
|
+
session: {
|
|
205
|
+
version: 1,
|
|
206
|
+
sessionId: desktopBoundedString(item.sessionId, "sessionId"),
|
|
207
|
+
isolation: item.isolation,
|
|
208
|
+
status: item.status,
|
|
209
|
+
...(item.applicationId === undefined
|
|
210
|
+
? {}
|
|
211
|
+
: { applicationId: desktopBoundedString(item.applicationId, "applicationId") }),
|
|
212
|
+
},
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
function desktopStopResult(value, operationId) {
|
|
216
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value) && "sessionId" in value)
|
|
217
|
+
return desktopSessionResult({ status: "succeeded", session: value }, operationId);
|
|
218
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value) && "status" in value) {
|
|
219
|
+
const status = value.status;
|
|
220
|
+
if (status === "unsupported" || status === "failed" || status === "cancelled" || status === "needs_user")
|
|
221
|
+
return desktopFailure(operationId, "desktop_adapter_failed", "Desktop session could not be stopped", status);
|
|
222
|
+
}
|
|
223
|
+
throw new Error("desktop-result-invalid");
|
|
224
|
+
}
|
|
225
|
+
export { desktopCapabilities, desktopObservationResult, desktopSessionResult, desktopStopResult };
|
|
226
|
+
//# sourceMappingURL=projection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projection.js","sourceRoot":"","sources":["../src/projection.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Inlined from agent-forge `src/profile/runtime-capabilities-desktop.ts`\n * (D-075 S3 extraction) so this package keeps its dependency closure limited\n * to the plugin SDK and typebox. Semantics are unchanged. Differences from\n * the host original:\n * - Desktop V1 types import from the package-local `types.ts` copy.\n * - The structural runtime guards (`desktopRuntime`/`desktopFullControlRuntime`)\n and the capability factory stay host-side or live in `capability.ts`.\n * Deliberate copy shared (subset-compatible) with\n * `plugins/desktop-windows-input/src/projection.ts`; keep both in sync.\n */\nimport type {\n\tDesktopCapabilityIdV1,\n\tDesktopControlIdentityV1,\n\tDesktopObservationV1,\n\tDesktopWindowIdentityV1,\n} from \"./types.ts\";\n\nconst DESKTOP_MAX_WINDOWS_V1 = 64;\nconst DESKTOP_MAX_CONTROLS_V1 = 256;\nexport const DESKTOP_MAX_STRING_CHARS_V1 = 256;\nconst DESKTOP_MAX_RESULT_BYTES_V1 = 64 * 1024;\nexport const DESKTOP_MAX_POSTCONDITIONS_V1 = 32;\nexport const DESKTOP_MAX_TYPE_TEXT_CHARS_V1 = 4096;\nexport const DESKTOP_MAX_REPLAY_ACTIONS_V1 = 32;\nconst DESKTOP_CAPABILITY_IDS_V1: readonly DesktopCapabilityIdV1[] = [\n\t\"desktop-session\",\n\t\"desktop-uia\",\n\t\"desktop-input\",\n\t\"desktop-vision\",\n\t\"desktop-replay\",\n];\n\nexport function desktopFailure(\n\toperationId: string,\n\tcode: string,\n\tmessage: string,\n\tstatus: \"failed\" | \"unsupported\" | \"cancelled\" | \"needs_user\" = \"failed\",\n) {\n\treturn {\n\t\tversion: 1 as const,\n\t\toperationId,\n\t\tstatus,\n\t\tsummary: message,\n\t\terror: { version: 1 as const, code, message },\n\t};\n}\n\nexport function desktopBoundedString(value: unknown, label: string): string {\n\tif (typeof value !== \"string\" || value.length > DESKTOP_MAX_STRING_CHARS_V1)\n\t\tthrow new Error(`desktop-result-budget:${label}`);\n\treturn value;\n}\n\n/// 观察投影专用:显示文本超长时截断而非抛异常(dogfood 2026-09-25 实测,真实桌面\n/// 单控件文本超上限很常见)。输入校验(type text/key/target)仍用 desktopBoundedString\n/// 严格拒绝——截断输入等于静默打错字。\nexport function desktopClampedString(value: unknown, label: string): string {\n\tif (typeof value !== \"string\") throw new Error(`desktop-result-budget:${label}`);\n\tif (value.length > DESKTOP_MAX_STRING_CHARS_V1) return value.slice(0, DESKTOP_MAX_STRING_CHARS_V1);\n\treturn value;\n}\n\nexport function desktopRequiredString(value: unknown, label: string): string {\n\tconst result = desktopBoundedString(value, label);\n\tif (result.trim() === \"\") throw new Error(`desktop-result-invalid:${label}`);\n\treturn result;\n}\n\nfunction desktopCapabilities(value: unknown): readonly DesktopCapabilityIdV1[] | undefined {\n\tif (!Array.isArray(value)) return undefined;\n\tconst capabilities = value.filter(\n\t\t(item): item is DesktopCapabilityIdV1 =>\n\t\t\ttypeof item === \"string\" && DESKTOP_CAPABILITY_IDS_V1.includes(item as DesktopCapabilityIdV1),\n\t);\n\tconst unique = [...new Set(capabilities)].slice(0, DESKTOP_CAPABILITY_IDS_V1.length);\n\treturn unique.length === 0 ? undefined : unique;\n}\n\nfunction desktopBounds(value: unknown): {\n\treadonly x: number;\n\treadonly y: number;\n\treadonly width: number;\n\treadonly height: number;\n} {\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value)) throw new Error(\"desktop-result-invalid\");\n\tconst record = value as Record<string, unknown>;\n\tconst bounds = { x: record.x, y: record.y, width: record.width, height: record.height };\n\tif (\n\t\tObject.values(bounds).some((item) => typeof item !== \"number\" || !Number.isFinite(item)) ||\n\t\t(bounds.width as number) < 0 ||\n\t\t(bounds.height as number) < 0\n\t)\n\t\tthrow new Error(\"desktop-result-invalid\");\n\treturn bounds as { x: number; y: number; width: number; height: number };\n}\n\nfunction projectDesktopWindow(value: unknown): DesktopWindowIdentityV1 {\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value)) throw new Error(\"desktop-result-invalid\");\n\tconst record = value as Record<string, unknown>;\n\tif (record.version !== 1) throw new Error(\"desktop-result-invalid\");\n\treturn {\n\t\tversion: 1,\n\t\twindowId: desktopClampedString(record.windowId, \"windowId\"),\n\t\tappId: desktopClampedString(record.appId, \"appId\"),\n\t\ttitle: desktopClampedString(record.title, \"title\"),\n\t\tbounds: desktopBounds(record.bounds),\n\t};\n}\n\nfunction projectDesktopControl(value: unknown): DesktopControlIdentityV1 {\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value)) throw new Error(\"desktop-result-invalid\");\n\tconst record = value as Record<string, unknown>;\n\tif (record.version !== 1 || typeof record.enabled !== \"boolean\") throw new Error(\"desktop-result-invalid\");\n\treturn {\n\t\tversion: 1,\n\t\tcontrolId: desktopClampedString(record.controlId, \"controlId\"),\n\t\twindowId: desktopClampedString(record.windowId, \"windowId\"),\n\t\trole: desktopClampedString(record.role, \"role\"),\n\t\tname: desktopClampedString(record.name, \"name\"),\n\t\tbounds: desktopBounds(record.bounds),\n\t\tenabled: record.enabled,\n\t\t...(record.value === undefined ? {} : { value: desktopClampedString(record.value, \"value\") }),\n\t};\n}\n\nexport function projectDesktopObservation(value: unknown): {\n\treadonly observation: DesktopObservationV1;\n\treadonly truncated: { readonly windows: boolean; readonly controls: boolean };\n} {\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value)) throw new Error(\"desktop-result-invalid\");\n\tconst record = value as Record<string, unknown>;\n\tif (\n\t\trecord.version !== 1 ||\n\t\ttypeof record.sessionId !== \"string\" ||\n\t\ttypeof record.observationId !== \"string\" ||\n\t\t(record.source !== \"mock\" && record.source !== \"windows-uia\") ||\n\t\t!Array.isArray(record.windows) ||\n\t\t!Array.isArray(record.controls)\n\t)\n\t\tthrow new Error(\"desktop-result-invalid\");\n\tconst windows = record.windows.slice(0, DESKTOP_MAX_WINDOWS_V1).map(projectDesktopWindow);\n\tconst controls = record.controls.slice(0, DESKTOP_MAX_CONTROLS_V1).map(projectDesktopControl);\n\tconst observation = {\n\t\tversion: 1 as const,\n\t\tsessionId: desktopClampedString(record.sessionId, \"sessionId\"),\n\t\tobservationId: desktopClampedString(record.observationId, \"observationId\"),\n\t\tsource: record.source,\n\t\twindows,\n\t\tcontrols,\n\t\t...(record.focusedControlId === undefined\n\t\t\t? {}\n\t\t\t: { focusedControlId: desktopClampedString(record.focusedControlId, \"focusedControlId\") }),\n\t} satisfies DesktopObservationV1;\n\treturn {\n\t\tobservation,\n\t\ttruncated: {\n\t\t\twindows: record.windows.length > DESKTOP_MAX_WINDOWS_V1,\n\t\t\tcontrols: record.controls.length > DESKTOP_MAX_CONTROLS_V1,\n\t\t},\n\t};\n}\n\nexport function desktopResultWithinBudget<T>(value: T): T {\n\tif (new TextEncoder().encode(JSON.stringify(value)).byteLength > DESKTOP_MAX_RESULT_BYTES_V1)\n\t\tthrow new Error(\"desktop-result-budget\");\n\treturn value;\n}\n\nfunction desktopObservationResult(value: unknown, operationId: string) {\n\tif (value !== null && typeof value === \"object\" && !Array.isArray(value) && \"observationId\" in value) {\n\t\tconst projected = projectDesktopObservation(value);\n\t\t// 真实桌面控件数轻松超出 64KB 结果预算(dogfood 2026-09-25 实测):超预算时\n\t\t// 控件/窗口逐级减半裁剪并如实标记 truncated,而不是让整次观察失败。\n\t\tconst controls = projected.observation.controls;\n\t\tconst windows = projected.observation.windows;\n\t\tlet controlCount = controls.length;\n\t\tlet windowCount = windows.length;\n\t\tfor (;;) {\n\t\t\ttry {\n\t\t\t\treturn desktopResultWithinBudget({\n\t\t\t\t\tversion: 1,\n\t\t\t\t\toperationId,\n\t\t\t\t\tstatus: \"succeeded\" as const,\n\t\t\t\t\tobservation: {\n\t\t\t\t\t\t...projected.observation,\n\t\t\t\t\t\tcontrols: controls.slice(0, controlCount),\n\t\t\t\t\t\twindows: windows.slice(0, windowCount),\n\t\t\t\t\t},\n\t\t\t\t\ttruncated: {\n\t\t\t\t\t\twindows: projected.truncated.windows || windowCount < windows.length,\n\t\t\t\t\t\tcontrols: projected.truncated.controls || controlCount < controls.length,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t} catch {\n\t\t\t\tif (controlCount > 0) controlCount = Math.floor(controlCount / 2);\n\t\t\t\telse if (windowCount > 0) windowCount = Math.floor(windowCount / 2);\n\t\t\t\telse throw new Error(\"desktop-result-budget\");\n\t\t\t}\n\t\t}\n\t}\n\tif (value !== null && typeof value === \"object\" && !Array.isArray(value) && \"status\" in value) {\n\t\tconst status = value.status;\n\t\tif (status === \"unsupported\" || status === \"failed\" || status === \"cancelled\" || status === \"needs_user\") {\n\t\t\tconst record0 = value as Record<string, unknown>;\n\t\t\tconst adapterError =\n\t\t\t\t\"error\" in record0 && record0.error !== null && typeof record0.error === \"object\"\n\t\t\t\t\t? (record0.error as Record<string, unknown>)\n\t\t\t\t\t: undefined;\n\t\t\tconst errorCode =\n\t\t\t\tadapterError && typeof adapterError.code === \"string\" ? adapterError.code : \"desktop_adapter_failed\";\n\t\t\tconst errorMessage =\n\t\t\t\tadapterError && typeof adapterError.message === \"string\"\n\t\t\t\t\t? adapterError.message\n\t\t\t\t\t: \"Desktop observation is unavailable\";\n\t\t\treturn desktopFailure(operationId, errorCode, errorMessage, status);\n\t\t}\n\t}\n\tthrow new Error(\"desktop-result-invalid\");\n}\n\nfunction desktopSessionResult(value: unknown, operationId: string) {\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value) || !(\"status\" in value))\n\t\tthrow new Error(\"desktop-result-invalid\");\n\tconst record = value as Record<string, unknown>;\n\tif (record.status !== \"succeeded\" && record.status !== \"unsupported\" && record.status !== \"failed\")\n\t\tthrow new Error(\"desktop-result-invalid\");\n\tif (record.status !== \"succeeded\")\n\t\treturn desktopFailure(\n\t\t\toperationId,\n\t\t\t\"desktop_adapter_unavailable\",\n\t\t\t\"Desktop session is unavailable\",\n\t\t\trecord.status,\n\t\t);\n\tconst session = record.session;\n\tif (session === null || typeof session !== \"object\" || Array.isArray(session))\n\t\tthrow new Error(\"desktop-result-invalid\");\n\tconst item = session as Record<string, unknown>;\n\tif (\n\t\titem.version !== 1 ||\n\t\ttypeof item.sessionId !== \"string\" ||\n\t\t(item.isolation !== \"foreground\" && item.isolation !== \"vm\" && item.isolation !== \"mock\") ||\n\t\t(item.status !== \"ready\" && item.status !== \"unavailable\" && item.status !== \"stopped\")\n\t)\n\t\tthrow new Error(\"desktop-result-invalid\");\n\treturn desktopResultWithinBudget({\n\t\tversion: 1,\n\t\toperationId,\n\t\tstatus: \"succeeded\" as const,\n\t\tsession: {\n\t\t\tversion: 1,\n\t\t\tsessionId: desktopBoundedString(item.sessionId, \"sessionId\"),\n\t\t\tisolation: item.isolation,\n\t\t\tstatus: item.status,\n\t\t\t...(item.applicationId === undefined\n\t\t\t\t? {}\n\t\t\t\t: { applicationId: desktopBoundedString(item.applicationId, \"applicationId\") }),\n\t\t},\n\t});\n}\n\nfunction desktopStopResult(value: unknown, operationId: string) {\n\tif (value !== null && typeof value === \"object\" && !Array.isArray(value) && \"sessionId\" in value)\n\t\treturn desktopSessionResult({ status: \"succeeded\", session: value }, operationId);\n\tif (value !== null && typeof value === \"object\" && !Array.isArray(value) && \"status\" in value) {\n\t\tconst status = value.status;\n\t\tif (status === \"unsupported\" || status === \"failed\" || status === \"cancelled\" || status === \"needs_user\")\n\t\t\treturn desktopFailure(operationId, \"desktop_adapter_failed\", \"Desktop session could not be stopped\", status);\n\t}\n\tthrow new Error(\"desktop-result-invalid\");\n}\n\nexport { desktopCapabilities, desktopObservationResult, desktopSessionResult, desktopStopResult };\n"]}
|
package/dist/shared.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inlined from agent-forge `src/profile/runtime-capabilities-shared.ts`
|
|
3
|
+
* (D-075 S3 extraction) so this package keeps its dependency closure limited
|
|
4
|
+
* to the plugin SDK and typebox. Semantics are unchanged; the artifact-ref
|
|
5
|
+
* schema helpers stay host-side because desktop tools do not use them.
|
|
6
|
+
* Deliberate copy shared with `plugins/desktop-windows-input/src/shared.ts`;
|
|
7
|
+
* keep both copies in sync.
|
|
8
|
+
*/
|
|
9
|
+
export declare function toolInvocation(first: unknown, second: unknown): {
|
|
10
|
+
readonly input: Record<string, unknown>;
|
|
11
|
+
readonly operationId: string;
|
|
12
|
+
};
|
|
13
|
+
export declare function signalFrom(value: unknown): AbortSignal | undefined;
|
|
14
|
+
export declare function nonEmptyString(value: unknown, label: string): string;
|
|
15
|
+
//# sourceMappingURL=shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../src/shared.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAUH,wBAAgB,cAAc,CAC7B,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,OAAO,GACb;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAK3E;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,GAAG,SAAS,CAElE;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAGpE","sourcesContent":["/**\n * Inlined from agent-forge `src/profile/runtime-capabilities-shared.ts`\n * (D-075 S3 extraction) so this package keeps its dependency closure limited\n * to the plugin SDK and typebox. Semantics are unchanged; the artifact-ref\n * schema helpers stay host-side because desktop tools do not use them.\n * Deliberate copy shared with `plugins/desktop-windows-input/src/shared.ts`;\n * keep both copies in sync.\n */\n\nfunction objectInput(first: unknown, second: unknown): Record<string, unknown> {\n\tconst value = second === undefined ? first : second;\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n\t\tthrow new Error(\"Plugin tool input must be an object\");\n\t}\n\treturn value as Record<string, unknown>;\n}\n\nexport function toolInvocation(\n\tfirst: unknown,\n\tsecond: unknown,\n): { readonly input: Record<string, unknown>; readonly operationId: string } {\n\treturn {\n\t\tinput: objectInput(first, second),\n\t\toperationId: typeof first === \"string\" && first.trim() !== \"\" ? first : \"profile-runtime-tool-call\",\n\t};\n}\n\nexport function signalFrom(value: unknown): AbortSignal | undefined {\n\treturn value instanceof AbortSignal ? value : undefined;\n}\n\nexport function nonEmptyString(value: unknown, label: string): string {\n\tif (typeof value !== \"string\" || value.trim() === \"\") throw new Error(`${label} must be a non-empty string`);\n\treturn value;\n}\n"]}
|
package/dist/shared.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inlined from agent-forge `src/profile/runtime-capabilities-shared.ts`
|
|
3
|
+
* (D-075 S3 extraction) so this package keeps its dependency closure limited
|
|
4
|
+
* to the plugin SDK and typebox. Semantics are unchanged; the artifact-ref
|
|
5
|
+
* schema helpers stay host-side because desktop tools do not use them.
|
|
6
|
+
* Deliberate copy shared with `plugins/desktop-windows-input/src/shared.ts`;
|
|
7
|
+
* keep both copies in sync.
|
|
8
|
+
*/
|
|
9
|
+
function objectInput(first, second) {
|
|
10
|
+
const value = second === undefined ? first : second;
|
|
11
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
12
|
+
throw new Error("Plugin tool input must be an object");
|
|
13
|
+
}
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
export function toolInvocation(first, second) {
|
|
17
|
+
return {
|
|
18
|
+
input: objectInput(first, second),
|
|
19
|
+
operationId: typeof first === "string" && first.trim() !== "" ? first : "profile-runtime-tool-call",
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export function signalFrom(value) {
|
|
23
|
+
return value instanceof AbortSignal ? value : undefined;
|
|
24
|
+
}
|
|
25
|
+
export function nonEmptyString(value, label) {
|
|
26
|
+
if (typeof value !== "string" || value.trim() === "")
|
|
27
|
+
throw new Error(`${label} must be a non-empty string`);
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../src/shared.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,SAAS,WAAW,CAAC,KAAc,EAAE,MAAe,EAA2B;IAC9E,MAAM,KAAK,GAAG,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;IACpD,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,KAAgC,CAAC;AAAA,CACxC;AAED,MAAM,UAAU,cAAc,CAC7B,KAAc,EACd,MAAe,EAC6D;IAC5E,OAAO;QACN,KAAK,EAAE,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC;QACjC,WAAW,EAAE,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,2BAA2B;KACnG,CAAC;AAAA,CACF;AAED,MAAM,UAAU,UAAU,CAAC,KAAc,EAA2B;IACnE,OAAO,KAAK,YAAY,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AAAA,CACxD;AAED,MAAM,UAAU,cAAc,CAAC,KAAc,EAAE,KAAa,EAAU;IACrE,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,6BAA6B,CAAC,CAAC;IAC7G,OAAO,KAAK,CAAC;AAAA,CACb","sourcesContent":["/**\n * Inlined from agent-forge `src/profile/runtime-capabilities-shared.ts`\n * (D-075 S3 extraction) so this package keeps its dependency closure limited\n * to the plugin SDK and typebox. Semantics are unchanged; the artifact-ref\n * schema helpers stay host-side because desktop tools do not use them.\n * Deliberate copy shared with `plugins/desktop-windows-input/src/shared.ts`;\n * keep both copies in sync.\n */\n\nfunction objectInput(first: unknown, second: unknown): Record<string, unknown> {\n\tconst value = second === undefined ? first : second;\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n\t\tthrow new Error(\"Plugin tool input must be an object\");\n\t}\n\treturn value as Record<string, unknown>;\n}\n\nexport function toolInvocation(\n\tfirst: unknown,\n\tsecond: unknown,\n): { readonly input: Record<string, unknown>; readonly operationId: string } {\n\treturn {\n\t\tinput: objectInput(first, second),\n\t\toperationId: typeof first === \"string\" && first.trim() !== \"\" ? first : \"profile-runtime-tool-call\",\n\t};\n}\n\nexport function signalFrom(value: unknown): AbortSignal | undefined {\n\treturn value instanceof AbortSignal ? value : undefined;\n}\n\nexport function nonEmptyString(value: unknown, label: string): string {\n\tif (typeof value !== \"string\" || value.trim() === \"\") throw new Error(`${label} must be a non-empty string`);\n\treturn value;\n}\n"]}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import type { PluginResultStatusV1 } from "@agent-forge/plugin-sdk";
|
|
2
|
+
/**
|
|
3
|
+
* Inlined from agent-forge `src/plugins/desktop/types.ts` (D-075 S3 extraction)
|
|
4
|
+
* so this package keeps its dependency closure limited to the plugin SDK and
|
|
5
|
+
* typebox. Semantics are unchanged. Differences from the host original:
|
|
6
|
+
* - `CapabilityRefV1`/`PluginPlatformBindingV1` import from `@agent-forge/plugin-sdk`.
|
|
7
|
+
* - The `agent-forge.desktop-control` test-only manifest contract types
|
|
8
|
+
* (`DesktopPluginManifestV1`, `DesktopCapabilityDeclarationV1`) stay host-side;
|
|
9
|
+
* they belong to the test-only mock plugin, not to this standalone package.
|
|
10
|
+
* This file is a deliberate copy shared (not imported) with
|
|
11
|
+
* `plugins/desktop-windows-input/src/types.ts`; keep both copies in sync.
|
|
12
|
+
*/
|
|
13
|
+
/** Stable capability ids owned by the desktop-control plugin family. */
|
|
14
|
+
export type DesktopCapabilityIdV1 = "desktop-session" | "desktop-uia" | "desktop-input" | "desktop-vision" | "desktop-replay";
|
|
15
|
+
export type DesktopSessionIsolationV1 = "mock" | "foreground" | "vm";
|
|
16
|
+
export type DesktopSessionStatusV1 = "ready" | "unavailable" | "stopped";
|
|
17
|
+
export interface DesktopSessionRequestV1 {
|
|
18
|
+
readonly version: 1;
|
|
19
|
+
readonly isolation: DesktopSessionIsolationV1;
|
|
20
|
+
readonly applicationId?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface DesktopSessionV1 {
|
|
23
|
+
readonly version: 1;
|
|
24
|
+
readonly sessionId: string;
|
|
25
|
+
readonly isolation: DesktopSessionIsolationV1;
|
|
26
|
+
readonly status: DesktopSessionStatusV1;
|
|
27
|
+
readonly applicationId?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface DesktopErrorV1 {
|
|
30
|
+
readonly version: 1;
|
|
31
|
+
readonly code: string;
|
|
32
|
+
readonly message: string;
|
|
33
|
+
readonly causeCode?: string;
|
|
34
|
+
}
|
|
35
|
+
export interface DesktopSessionResultV1 {
|
|
36
|
+
readonly status: Extract<PluginResultStatusV1, "succeeded" | "unsupported" | "failed">;
|
|
37
|
+
readonly session?: DesktopSessionV1;
|
|
38
|
+
readonly error?: DesktopErrorV1;
|
|
39
|
+
}
|
|
40
|
+
export interface DesktopWindowIdentityV1 {
|
|
41
|
+
readonly version: 1;
|
|
42
|
+
readonly windowId: string;
|
|
43
|
+
readonly appId: string;
|
|
44
|
+
readonly title: string;
|
|
45
|
+
readonly bounds: DesktopBoundsV1;
|
|
46
|
+
}
|
|
47
|
+
export interface DesktopControlIdentityV1 {
|
|
48
|
+
readonly version: 1;
|
|
49
|
+
readonly controlId: string;
|
|
50
|
+
readonly windowId: string;
|
|
51
|
+
readonly role: string;
|
|
52
|
+
readonly name: string;
|
|
53
|
+
readonly bounds: DesktopBoundsV1;
|
|
54
|
+
readonly enabled: boolean;
|
|
55
|
+
readonly value?: string;
|
|
56
|
+
}
|
|
57
|
+
export interface DesktopBoundsV1 {
|
|
58
|
+
readonly x: number;
|
|
59
|
+
readonly y: number;
|
|
60
|
+
readonly width: number;
|
|
61
|
+
readonly height: number;
|
|
62
|
+
}
|
|
63
|
+
export interface DesktopObservationV1 {
|
|
64
|
+
readonly version: 1;
|
|
65
|
+
readonly sessionId: string;
|
|
66
|
+
readonly observationId: string;
|
|
67
|
+
readonly source: "mock" | "windows-uia";
|
|
68
|
+
readonly windows: readonly DesktopWindowIdentityV1[];
|
|
69
|
+
readonly controls: readonly DesktopControlIdentityV1[];
|
|
70
|
+
readonly focusedControlId?: string;
|
|
71
|
+
}
|
|
72
|
+
export type DesktopTargetRefV1 = {
|
|
73
|
+
readonly kind: "window";
|
|
74
|
+
readonly windowId: string;
|
|
75
|
+
} | {
|
|
76
|
+
readonly kind: "control";
|
|
77
|
+
readonly controlId: string;
|
|
78
|
+
readonly windowId?: string;
|
|
79
|
+
};
|
|
80
|
+
export type DesktopActionKindV1 = "focus" | "click" | "type" | "key" | "scroll" | "submit" | "uac" | "password" | "admin" | "payment" | "external-submit";
|
|
81
|
+
/**
|
|
82
|
+
* Actions that must pause at the host/user boundary before any input is sent.
|
|
83
|
+
* This policy belongs to the desktop plugin, not Agent Core.
|
|
84
|
+
*/
|
|
85
|
+
export declare const DESKTOP_USER_CONFIRMATION_ACTIONS: readonly ["uac", "password", "admin", "payment", "external-submit"];
|
|
86
|
+
export declare const requiresDesktopUserConfirmation: (kind: DesktopActionKindV1) => boolean;
|
|
87
|
+
export interface DesktopActionV1 {
|
|
88
|
+
readonly version: 1;
|
|
89
|
+
readonly kind: DesktopActionKindV1;
|
|
90
|
+
readonly target?: DesktopTargetRefV1;
|
|
91
|
+
readonly text?: string;
|
|
92
|
+
readonly key?: string;
|
|
93
|
+
}
|
|
94
|
+
export type DesktopPostconditionV1 = {
|
|
95
|
+
readonly kind: "window-exists";
|
|
96
|
+
readonly windowId: string;
|
|
97
|
+
} | {
|
|
98
|
+
readonly kind: "control-exists";
|
|
99
|
+
readonly controlId: string;
|
|
100
|
+
} | {
|
|
101
|
+
readonly kind: "focused";
|
|
102
|
+
readonly controlId: string;
|
|
103
|
+
} | {
|
|
104
|
+
readonly kind: "property-equals";
|
|
105
|
+
readonly target: DesktopTargetRefV1;
|
|
106
|
+
readonly property: "enabled" | "value" | "name";
|
|
107
|
+
readonly expected: boolean | string;
|
|
108
|
+
};
|
|
109
|
+
export interface DesktopOperationRequestV1 {
|
|
110
|
+
readonly version: 1;
|
|
111
|
+
readonly operationId: string;
|
|
112
|
+
readonly sessionId: string;
|
|
113
|
+
readonly action: DesktopActionV1;
|
|
114
|
+
readonly postconditions?: readonly DesktopPostconditionV1[];
|
|
115
|
+
readonly reobserveAfterAction?: boolean;
|
|
116
|
+
}
|
|
117
|
+
export interface DesktopVerificationV1 {
|
|
118
|
+
readonly status: "passed" | "failed" | "unknown";
|
|
119
|
+
readonly checks: readonly string[];
|
|
120
|
+
}
|
|
121
|
+
export interface DesktopOperationResultV1 {
|
|
122
|
+
readonly version: 1;
|
|
123
|
+
readonly operationId: string;
|
|
124
|
+
readonly status: PluginResultStatusV1;
|
|
125
|
+
readonly summary: string;
|
|
126
|
+
readonly observation?: DesktopObservationV1;
|
|
127
|
+
readonly verification?: DesktopVerificationV1;
|
|
128
|
+
readonly error?: DesktopErrorV1;
|
|
129
|
+
}
|
|
130
|
+
export interface DesktopReplayRequestV1 {
|
|
131
|
+
readonly version: 1;
|
|
132
|
+
readonly sessionId: string;
|
|
133
|
+
readonly operations: readonly DesktopOperationRequestV1[];
|
|
134
|
+
readonly stopOnFailure: boolean;
|
|
135
|
+
}
|
|
136
|
+
/** Returns the first operation id that would cross the replay session boundary. */
|
|
137
|
+
export declare const findDesktopReplaySessionMismatch: (request: DesktopReplayRequestV1) => string | undefined;
|
|
138
|
+
export interface DesktopReplayResultV1 {
|
|
139
|
+
readonly version: 1;
|
|
140
|
+
readonly status: Extract<PluginResultStatusV1, "succeeded" | "failed" | "cancelled" | "needs_user">;
|
|
141
|
+
readonly results: readonly DesktopOperationResultV1[];
|
|
142
|
+
}
|
|
143
|
+
export interface DesktopAdapterV1 {
|
|
144
|
+
readonly adapterId: string;
|
|
145
|
+
readonly adapterVersion: string;
|
|
146
|
+
readonly capabilities: readonly DesktopCapabilityIdV1[];
|
|
147
|
+
openSession(request: DesktopSessionRequestV1): DesktopSessionResultV1;
|
|
148
|
+
observe(sessionId: string): DesktopObservationV1 | DesktopOperationResultV1;
|
|
149
|
+
reobserve(sessionId: string): DesktopObservationV1 | DesktopOperationResultV1;
|
|
150
|
+
execute(request: DesktopOperationRequestV1): DesktopOperationResultV1;
|
|
151
|
+
stop(sessionId: string): DesktopSessionV1 | DesktopOperationResultV1;
|
|
152
|
+
replay(request: DesktopReplayRequestV1): DesktopReplayResultV1;
|
|
153
|
+
}
|
|
154
|
+
/** Result returned by a host UI Automation capability probe. */
|
|
155
|
+
export interface DesktopWindowsProbeV1 {
|
|
156
|
+
readonly available: boolean;
|
|
157
|
+
readonly platform: string;
|
|
158
|
+
readonly driver: "windows-uia";
|
|
159
|
+
/** Capabilities that the host can expose without relying on a higher-risk facade. */
|
|
160
|
+
readonly capabilities?: readonly DesktopCapabilityIdV1[];
|
|
161
|
+
readonly reason?: string;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Synchronous host boundary used by the Windows adapter. Implementations may
|
|
165
|
+
* use UI Automation, an OS broker, or a test driver. The adapter never
|
|
166
|
+
* invents observations when this boundary reports unavailable.
|
|
167
|
+
*/
|
|
168
|
+
export interface DesktopWindowsDriverV1 {
|
|
169
|
+
readonly driverId: string;
|
|
170
|
+
readonly driverVersion: string;
|
|
171
|
+
probe(): DesktopWindowsProbeV1;
|
|
172
|
+
openSession(request: DesktopSessionRequestV1): DesktopSessionResultV1;
|
|
173
|
+
observe(sessionId: string): DesktopObservationV1 | DesktopOperationResultV1;
|
|
174
|
+
execute(request: DesktopOperationRequestV1): DesktopOperationResultV1;
|
|
175
|
+
stop(sessionId: string): DesktopSessionV1 | DesktopOperationResultV1;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Production-safe, read-only desktop boundary. It deliberately omits
|
|
179
|
+
* execute/replay so a host cannot accidentally expose input through the
|
|
180
|
+
* observe plugin. The full DesktopAdapter remains a separate test/high-risk
|
|
181
|
+
* contract.
|
|
182
|
+
*/
|
|
183
|
+
export interface DesktopReadonlyAdapterV1 {
|
|
184
|
+
readonly adapterId: string;
|
|
185
|
+
readonly adapterVersion: string;
|
|
186
|
+
probe(): DesktopWindowsProbeV1;
|
|
187
|
+
openSession(request: DesktopSessionRequestV1): DesktopSessionResultV1;
|
|
188
|
+
observe(sessionId: string): DesktopObservationV1 | DesktopOperationResultV1;
|
|
189
|
+
reobserve(sessionId: string): DesktopObservationV1 | DesktopOperationResultV1;
|
|
190
|
+
stop(sessionId: string): DesktopSessionV1 | DesktopOperationResultV1;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Production host boundary for intentionally bounded desktop input. This is
|
|
194
|
+
* separate from DesktopReadonlyAdapterV1 so observing a desktop never
|
|
195
|
+
* accidentally grants input, and replay is optional: adapters that expose it
|
|
196
|
+
* keep the session-mismatch gate and the needs-user confirmation per action.
|
|
197
|
+
*/
|
|
198
|
+
export interface DesktopFullControlAdapterV1 extends DesktopReadonlyAdapterV1 {
|
|
199
|
+
execute(request: DesktopOperationRequestV1): DesktopOperationResultV1;
|
|
200
|
+
replay?(request: DesktopReplayRequestV1): DesktopReplayResultV1;
|
|
201
|
+
}
|
|
202
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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","sourcesContent":["import type { PluginResultStatusV1 } from \"@agent-forge/plugin-sdk\";\n\n/**\n * Inlined from agent-forge `src/plugins/desktop/types.ts` (D-075 S3 extraction)\n * so this package keeps its dependency closure limited to the plugin SDK and\n * typebox. Semantics are unchanged. Differences from the host original:\n * - `CapabilityRefV1`/`PluginPlatformBindingV1` import from `@agent-forge/plugin-sdk`.\n * - The `agent-forge.desktop-control` test-only manifest contract types\n * (`DesktopPluginManifestV1`, `DesktopCapabilityDeclarationV1`) stay host-side;\n * they belong to the test-only mock plugin, not to this standalone package.\n * This file is a deliberate copy shared (not imported) with\n * `plugins/desktop-windows-input/src/types.ts`; keep both copies in sync.\n */\n\n/** Stable capability ids owned by the desktop-control plugin family. */\nexport type DesktopCapabilityIdV1 =\n\t| \"desktop-session\"\n\t| \"desktop-uia\"\n\t| \"desktop-input\"\n\t| \"desktop-vision\"\n\t| \"desktop-replay\";\n\nexport type DesktopSessionIsolationV1 = \"mock\" | \"foreground\" | \"vm\";\nexport type DesktopSessionStatusV1 = \"ready\" | \"unavailable\" | \"stopped\";\n\nexport interface DesktopSessionRequestV1 {\n\treadonly version: 1;\n\treadonly isolation: DesktopSessionIsolationV1;\n\treadonly applicationId?: string;\n}\n\nexport interface DesktopSessionV1 {\n\treadonly version: 1;\n\treadonly sessionId: string;\n\treadonly isolation: DesktopSessionIsolationV1;\n\treadonly status: DesktopSessionStatusV1;\n\treadonly applicationId?: string;\n}\n\nexport interface DesktopErrorV1 {\n\treadonly version: 1;\n\treadonly code: string;\n\treadonly message: string;\n\treadonly causeCode?: string;\n}\n\nexport interface DesktopSessionResultV1 {\n\treadonly status: Extract<PluginResultStatusV1, \"succeeded\" | \"unsupported\" | \"failed\">;\n\treadonly session?: DesktopSessionV1;\n\treadonly error?: DesktopErrorV1;\n}\n\nexport interface DesktopWindowIdentityV1 {\n\treadonly version: 1;\n\treadonly windowId: string;\n\treadonly appId: string;\n\treadonly title: string;\n\treadonly bounds: DesktopBoundsV1;\n}\n\nexport interface DesktopControlIdentityV1 {\n\treadonly version: 1;\n\treadonly controlId: string;\n\treadonly windowId: string;\n\treadonly role: string;\n\treadonly name: string;\n\treadonly bounds: DesktopBoundsV1;\n\treadonly enabled: boolean;\n\treadonly value?: string;\n}\n\nexport interface DesktopBoundsV1 {\n\treadonly x: number;\n\treadonly y: number;\n\treadonly width: number;\n\treadonly height: number;\n}\n\nexport interface DesktopObservationV1 {\n\treadonly version: 1;\n\treadonly sessionId: string;\n\treadonly observationId: string;\n\treadonly source: \"mock\" | \"windows-uia\";\n\treadonly windows: readonly DesktopWindowIdentityV1[];\n\treadonly controls: readonly DesktopControlIdentityV1[];\n\treadonly focusedControlId?: string;\n}\n\nexport type DesktopTargetRefV1 =\n\t| { readonly kind: \"window\"; readonly windowId: string }\n\t| { readonly kind: \"control\"; readonly controlId: string; readonly windowId?: string };\n\nexport type DesktopActionKindV1 =\n\t| \"focus\"\n\t| \"click\"\n\t| \"type\"\n\t| \"key\"\n\t| \"scroll\"\n\t| \"submit\"\n\t| \"uac\"\n\t| \"password\"\n\t| \"admin\"\n\t| \"payment\"\n\t| \"external-submit\";\n\n/**\n * Actions that must pause at the host/user boundary before any input is sent.\n * This policy belongs to the desktop plugin, not Agent Core.\n */\nexport const DESKTOP_USER_CONFIRMATION_ACTIONS = Object.freeze([\n\t\"uac\",\n\t\"password\",\n\t\"admin\",\n\t\"payment\",\n\t\"external-submit\",\n] as const satisfies readonly DesktopActionKindV1[]);\n\nexport const requiresDesktopUserConfirmation = (kind: DesktopActionKindV1): boolean =>\n\t(DESKTOP_USER_CONFIRMATION_ACTIONS as readonly DesktopActionKindV1[]).includes(kind);\n\nexport interface DesktopActionV1 {\n\treadonly version: 1;\n\treadonly kind: DesktopActionKindV1;\n\treadonly target?: DesktopTargetRefV1;\n\treadonly text?: string;\n\treadonly key?: string;\n}\n\nexport type DesktopPostconditionV1 =\n\t| { readonly kind: \"window-exists\"; readonly windowId: string }\n\t| { readonly kind: \"control-exists\"; readonly controlId: string }\n\t| { readonly kind: \"focused\"; readonly controlId: string }\n\t| {\n\t\t\treadonly kind: \"property-equals\";\n\t\t\treadonly target: DesktopTargetRefV1;\n\t\t\treadonly property: \"enabled\" | \"value\" | \"name\";\n\t\t\treadonly expected: boolean | string;\n\t };\n\nexport interface DesktopOperationRequestV1 {\n\treadonly version: 1;\n\treadonly operationId: string;\n\treadonly sessionId: string;\n\treadonly action: DesktopActionV1;\n\treadonly postconditions?: readonly DesktopPostconditionV1[];\n\treadonly reobserveAfterAction?: boolean;\n}\n\nexport interface DesktopVerificationV1 {\n\treadonly status: \"passed\" | \"failed\" | \"unknown\";\n\treadonly checks: readonly string[];\n}\n\nexport interface DesktopOperationResultV1 {\n\treadonly version: 1;\n\treadonly operationId: string;\n\treadonly status: PluginResultStatusV1;\n\treadonly summary: string;\n\treadonly observation?: DesktopObservationV1;\n\treadonly verification?: DesktopVerificationV1;\n\treadonly error?: DesktopErrorV1;\n}\n\nexport interface DesktopReplayRequestV1 {\n\treadonly version: 1;\n\treadonly sessionId: string;\n\treadonly operations: readonly DesktopOperationRequestV1[];\n\treadonly stopOnFailure: boolean;\n}\n\n/** Returns the first operation id that would cross the replay session boundary. */\nexport const findDesktopReplaySessionMismatch = (request: DesktopReplayRequestV1): string | undefined => {\n\tfor (const operation of request.operations) {\n\t\tif (operation.sessionId !== request.sessionId) return operation.operationId;\n\t}\n\treturn undefined;\n};\n\nexport interface DesktopReplayResultV1 {\n\treadonly version: 1;\n\treadonly status: Extract<PluginResultStatusV1, \"succeeded\" | \"failed\" | \"cancelled\" | \"needs_user\">;\n\treadonly results: readonly DesktopOperationResultV1[];\n}\n\nexport interface DesktopAdapterV1 {\n\treadonly adapterId: string;\n\treadonly adapterVersion: string;\n\treadonly capabilities: readonly DesktopCapabilityIdV1[];\n\topenSession(request: DesktopSessionRequestV1): DesktopSessionResultV1;\n\tobserve(sessionId: string): DesktopObservationV1 | DesktopOperationResultV1;\n\treobserve(sessionId: string): DesktopObservationV1 | DesktopOperationResultV1;\n\texecute(request: DesktopOperationRequestV1): DesktopOperationResultV1;\n\tstop(sessionId: string): DesktopSessionV1 | DesktopOperationResultV1;\n\treplay(request: DesktopReplayRequestV1): DesktopReplayResultV1;\n}\n\n/** Result returned by a host UI Automation capability probe. */\nexport interface DesktopWindowsProbeV1 {\n\treadonly available: boolean;\n\treadonly platform: string;\n\treadonly driver: \"windows-uia\";\n\t/** Capabilities that the host can expose without relying on a higher-risk facade. */\n\treadonly capabilities?: readonly DesktopCapabilityIdV1[];\n\treadonly reason?: string;\n}\n\n/**\n * Synchronous host boundary used by the Windows adapter. Implementations may\n * use UI Automation, an OS broker, or a test driver. The adapter never\n * invents observations when this boundary reports unavailable.\n */\nexport interface DesktopWindowsDriverV1 {\n\treadonly driverId: string;\n\treadonly driverVersion: string;\n\tprobe(): DesktopWindowsProbeV1;\n\topenSession(request: DesktopSessionRequestV1): DesktopSessionResultV1;\n\tobserve(sessionId: string): DesktopObservationV1 | DesktopOperationResultV1;\n\texecute(request: DesktopOperationRequestV1): DesktopOperationResultV1;\n\tstop(sessionId: string): DesktopSessionV1 | DesktopOperationResultV1;\n}\n\n/**\n * Production-safe, read-only desktop boundary. It deliberately omits\n * execute/replay so a host cannot accidentally expose input through the\n * observe plugin. The full DesktopAdapter remains a separate test/high-risk\n * contract.\n */\nexport interface DesktopReadonlyAdapterV1 {\n\treadonly adapterId: string;\n\treadonly adapterVersion: string;\n\tprobe(): DesktopWindowsProbeV1;\n\topenSession(request: DesktopSessionRequestV1): DesktopSessionResultV1;\n\tobserve(sessionId: string): DesktopObservationV1 | DesktopOperationResultV1;\n\treobserve(sessionId: string): DesktopObservationV1 | DesktopOperationResultV1;\n\tstop(sessionId: string): DesktopSessionV1 | DesktopOperationResultV1;\n}\n\n/**\n * Production host boundary for intentionally bounded desktop input. This is\n * separate from DesktopReadonlyAdapterV1 so observing a desktop never\n * accidentally grants input, and replay is optional: adapters that expose it\n * keep the session-mismatch gate and the needs-user confirmation per action.\n */\nexport interface DesktopFullControlAdapterV1 extends DesktopReadonlyAdapterV1 {\n\texecute(request: DesktopOperationRequestV1): DesktopOperationResultV1;\n\treplay?(request: DesktopReplayRequestV1): DesktopReplayResultV1;\n}\n"]}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Actions that must pause at the host/user boundary before any input is sent.
|
|
3
|
+
* This policy belongs to the desktop plugin, not Agent Core.
|
|
4
|
+
*/
|
|
5
|
+
export const DESKTOP_USER_CONFIRMATION_ACTIONS = Object.freeze([
|
|
6
|
+
"uac",
|
|
7
|
+
"password",
|
|
8
|
+
"admin",
|
|
9
|
+
"payment",
|
|
10
|
+
"external-submit",
|
|
11
|
+
]);
|
|
12
|
+
export const requiresDesktopUserConfirmation = (kind) => DESKTOP_USER_CONFIRMATION_ACTIONS.includes(kind);
|
|
13
|
+
/** Returns the first operation id that would cross the replay session boundary. */
|
|
14
|
+
export const findDesktopReplaySessionMismatch = (request) => {
|
|
15
|
+
for (const operation of request.operations) {
|
|
16
|
+
if (operation.sessionId !== request.sessionId)
|
|
17
|
+
return operation.operationId;
|
|
18
|
+
}
|
|
19
|
+
return undefined;
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAyGA;;;GAGG;AACH,MAAM,CAAC,MAAM,iCAAiC,GAAG,MAAM,CAAC,MAAM,CAAC;IAC9D,KAAK;IACL,UAAU;IACV,OAAO;IACP,SAAS;IACT,iBAAiB;CACiC,CAAC,CAAC;AAErD,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAAC,IAAyB,EAAW,EAAE,CACpF,iCAAoE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAoDtF,mFAAmF;AACnF,MAAM,CAAC,MAAM,gCAAgC,GAAG,CAAC,OAA+B,EAAsB,EAAE,CAAC;IACxG,KAAK,MAAM,SAAS,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;QAC5C,IAAI,SAAS,CAAC,SAAS,KAAK,OAAO,CAAC,SAAS;YAAE,OAAO,SAAS,CAAC,WAAW,CAAC;IAC7E,CAAC;IACD,OAAO,SAAS,CAAC;AAAA,CACjB,CAAC","sourcesContent":["import type { PluginResultStatusV1 } from \"@agent-forge/plugin-sdk\";\n\n/**\n * Inlined from agent-forge `src/plugins/desktop/types.ts` (D-075 S3 extraction)\n * so this package keeps its dependency closure limited to the plugin SDK and\n * typebox. Semantics are unchanged. Differences from the host original:\n * - `CapabilityRefV1`/`PluginPlatformBindingV1` import from `@agent-forge/plugin-sdk`.\n * - The `agent-forge.desktop-control` test-only manifest contract types\n * (`DesktopPluginManifestV1`, `DesktopCapabilityDeclarationV1`) stay host-side;\n * they belong to the test-only mock plugin, not to this standalone package.\n * This file is a deliberate copy shared (not imported) with\n * `plugins/desktop-windows-input/src/types.ts`; keep both copies in sync.\n */\n\n/** Stable capability ids owned by the desktop-control plugin family. */\nexport type DesktopCapabilityIdV1 =\n\t| \"desktop-session\"\n\t| \"desktop-uia\"\n\t| \"desktop-input\"\n\t| \"desktop-vision\"\n\t| \"desktop-replay\";\n\nexport type DesktopSessionIsolationV1 = \"mock\" | \"foreground\" | \"vm\";\nexport type DesktopSessionStatusV1 = \"ready\" | \"unavailable\" | \"stopped\";\n\nexport interface DesktopSessionRequestV1 {\n\treadonly version: 1;\n\treadonly isolation: DesktopSessionIsolationV1;\n\treadonly applicationId?: string;\n}\n\nexport interface DesktopSessionV1 {\n\treadonly version: 1;\n\treadonly sessionId: string;\n\treadonly isolation: DesktopSessionIsolationV1;\n\treadonly status: DesktopSessionStatusV1;\n\treadonly applicationId?: string;\n}\n\nexport interface DesktopErrorV1 {\n\treadonly version: 1;\n\treadonly code: string;\n\treadonly message: string;\n\treadonly causeCode?: string;\n}\n\nexport interface DesktopSessionResultV1 {\n\treadonly status: Extract<PluginResultStatusV1, \"succeeded\" | \"unsupported\" | \"failed\">;\n\treadonly session?: DesktopSessionV1;\n\treadonly error?: DesktopErrorV1;\n}\n\nexport interface DesktopWindowIdentityV1 {\n\treadonly version: 1;\n\treadonly windowId: string;\n\treadonly appId: string;\n\treadonly title: string;\n\treadonly bounds: DesktopBoundsV1;\n}\n\nexport interface DesktopControlIdentityV1 {\n\treadonly version: 1;\n\treadonly controlId: string;\n\treadonly windowId: string;\n\treadonly role: string;\n\treadonly name: string;\n\treadonly bounds: DesktopBoundsV1;\n\treadonly enabled: boolean;\n\treadonly value?: string;\n}\n\nexport interface DesktopBoundsV1 {\n\treadonly x: number;\n\treadonly y: number;\n\treadonly width: number;\n\treadonly height: number;\n}\n\nexport interface DesktopObservationV1 {\n\treadonly version: 1;\n\treadonly sessionId: string;\n\treadonly observationId: string;\n\treadonly source: \"mock\" | \"windows-uia\";\n\treadonly windows: readonly DesktopWindowIdentityV1[];\n\treadonly controls: readonly DesktopControlIdentityV1[];\n\treadonly focusedControlId?: string;\n}\n\nexport type DesktopTargetRefV1 =\n\t| { readonly kind: \"window\"; readonly windowId: string }\n\t| { readonly kind: \"control\"; readonly controlId: string; readonly windowId?: string };\n\nexport type DesktopActionKindV1 =\n\t| \"focus\"\n\t| \"click\"\n\t| \"type\"\n\t| \"key\"\n\t| \"scroll\"\n\t| \"submit\"\n\t| \"uac\"\n\t| \"password\"\n\t| \"admin\"\n\t| \"payment\"\n\t| \"external-submit\";\n\n/**\n * Actions that must pause at the host/user boundary before any input is sent.\n * This policy belongs to the desktop plugin, not Agent Core.\n */\nexport const DESKTOP_USER_CONFIRMATION_ACTIONS = Object.freeze([\n\t\"uac\",\n\t\"password\",\n\t\"admin\",\n\t\"payment\",\n\t\"external-submit\",\n] as const satisfies readonly DesktopActionKindV1[]);\n\nexport const requiresDesktopUserConfirmation = (kind: DesktopActionKindV1): boolean =>\n\t(DESKTOP_USER_CONFIRMATION_ACTIONS as readonly DesktopActionKindV1[]).includes(kind);\n\nexport interface DesktopActionV1 {\n\treadonly version: 1;\n\treadonly kind: DesktopActionKindV1;\n\treadonly target?: DesktopTargetRefV1;\n\treadonly text?: string;\n\treadonly key?: string;\n}\n\nexport type DesktopPostconditionV1 =\n\t| { readonly kind: \"window-exists\"; readonly windowId: string }\n\t| { readonly kind: \"control-exists\"; readonly controlId: string }\n\t| { readonly kind: \"focused\"; readonly controlId: string }\n\t| {\n\t\t\treadonly kind: \"property-equals\";\n\t\t\treadonly target: DesktopTargetRefV1;\n\t\t\treadonly property: \"enabled\" | \"value\" | \"name\";\n\t\t\treadonly expected: boolean | string;\n\t };\n\nexport interface DesktopOperationRequestV1 {\n\treadonly version: 1;\n\treadonly operationId: string;\n\treadonly sessionId: string;\n\treadonly action: DesktopActionV1;\n\treadonly postconditions?: readonly DesktopPostconditionV1[];\n\treadonly reobserveAfterAction?: boolean;\n}\n\nexport interface DesktopVerificationV1 {\n\treadonly status: \"passed\" | \"failed\" | \"unknown\";\n\treadonly checks: readonly string[];\n}\n\nexport interface DesktopOperationResultV1 {\n\treadonly version: 1;\n\treadonly operationId: string;\n\treadonly status: PluginResultStatusV1;\n\treadonly summary: string;\n\treadonly observation?: DesktopObservationV1;\n\treadonly verification?: DesktopVerificationV1;\n\treadonly error?: DesktopErrorV1;\n}\n\nexport interface DesktopReplayRequestV1 {\n\treadonly version: 1;\n\treadonly sessionId: string;\n\treadonly operations: readonly DesktopOperationRequestV1[];\n\treadonly stopOnFailure: boolean;\n}\n\n/** Returns the first operation id that would cross the replay session boundary. */\nexport const findDesktopReplaySessionMismatch = (request: DesktopReplayRequestV1): string | undefined => {\n\tfor (const operation of request.operations) {\n\t\tif (operation.sessionId !== request.sessionId) return operation.operationId;\n\t}\n\treturn undefined;\n};\n\nexport interface DesktopReplayResultV1 {\n\treadonly version: 1;\n\treadonly status: Extract<PluginResultStatusV1, \"succeeded\" | \"failed\" | \"cancelled\" | \"needs_user\">;\n\treadonly results: readonly DesktopOperationResultV1[];\n}\n\nexport interface DesktopAdapterV1 {\n\treadonly adapterId: string;\n\treadonly adapterVersion: string;\n\treadonly capabilities: readonly DesktopCapabilityIdV1[];\n\topenSession(request: DesktopSessionRequestV1): DesktopSessionResultV1;\n\tobserve(sessionId: string): DesktopObservationV1 | DesktopOperationResultV1;\n\treobserve(sessionId: string): DesktopObservationV1 | DesktopOperationResultV1;\n\texecute(request: DesktopOperationRequestV1): DesktopOperationResultV1;\n\tstop(sessionId: string): DesktopSessionV1 | DesktopOperationResultV1;\n\treplay(request: DesktopReplayRequestV1): DesktopReplayResultV1;\n}\n\n/** Result returned by a host UI Automation capability probe. */\nexport interface DesktopWindowsProbeV1 {\n\treadonly available: boolean;\n\treadonly platform: string;\n\treadonly driver: \"windows-uia\";\n\t/** Capabilities that the host can expose without relying on a higher-risk facade. */\n\treadonly capabilities?: readonly DesktopCapabilityIdV1[];\n\treadonly reason?: string;\n}\n\n/**\n * Synchronous host boundary used by the Windows adapter. Implementations may\n * use UI Automation, an OS broker, or a test driver. The adapter never\n * invents observations when this boundary reports unavailable.\n */\nexport interface DesktopWindowsDriverV1 {\n\treadonly driverId: string;\n\treadonly driverVersion: string;\n\tprobe(): DesktopWindowsProbeV1;\n\topenSession(request: DesktopSessionRequestV1): DesktopSessionResultV1;\n\tobserve(sessionId: string): DesktopObservationV1 | DesktopOperationResultV1;\n\texecute(request: DesktopOperationRequestV1): DesktopOperationResultV1;\n\tstop(sessionId: string): DesktopSessionV1 | DesktopOperationResultV1;\n}\n\n/**\n * Production-safe, read-only desktop boundary. It deliberately omits\n * execute/replay so a host cannot accidentally expose input through the\n * observe plugin. The full DesktopAdapter remains a separate test/high-risk\n * contract.\n */\nexport interface DesktopReadonlyAdapterV1 {\n\treadonly adapterId: string;\n\treadonly adapterVersion: string;\n\tprobe(): DesktopWindowsProbeV1;\n\topenSession(request: DesktopSessionRequestV1): DesktopSessionResultV1;\n\tobserve(sessionId: string): DesktopObservationV1 | DesktopOperationResultV1;\n\treobserve(sessionId: string): DesktopObservationV1 | DesktopOperationResultV1;\n\tstop(sessionId: string): DesktopSessionV1 | DesktopOperationResultV1;\n}\n\n/**\n * Production host boundary for intentionally bounded desktop input. This is\n * separate from DesktopReadonlyAdapterV1 so observing a desktop never\n * accidentally grants input, and replay is optional: adapters that expose it\n * keep the session-mismatch gate and the needs-user confirmation per action.\n */\nexport interface DesktopFullControlAdapterV1 extends DesktopReadonlyAdapterV1 {\n\texecute(request: DesktopOperationRequestV1): DesktopOperationResultV1;\n\treplay?(request: DesktopReplayRequestV1): DesktopReplayResultV1;\n}\n"]}
|