@ycheung5/pi-computer-use 0.0.0-stage → 0.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/GLOSSARY.md +38 -0
- package/LICENSE +21 -0
- package/README.md +165 -2
- package/assets/accessibility.cs +208 -0
- package/assets/browser-indicators.cs +37 -0
- package/assets/capture.cs +215 -0
- package/assets/clipboard.cs +197 -0
- package/assets/controls.cs +249 -0
- package/assets/indicator-preview.png +0 -0
- package/assets/indicators.cs +252 -0
- package/assets/node-LICENSE.txt +2732 -0
- package/assets/ocr.cs +86 -0
- package/assets/ownership.cs +59 -0
- package/assets/pointer.cs +229 -0
- package/assets/puppeteer-LICENSE.txt +202 -0
- package/assets/readme-banner.svg +33 -0
- package/assets/stop.cs +197 -0
- package/assets/text.cs +249 -0
- package/assets/wgc.cs +167 -0
- package/assets/window-management.cs +217 -0
- package/assets/window-marker.cs +23 -0
- package/assets/window-references.cs +80 -0
- package/assets/windows.cs +127 -0
- package/dist/accessibility.d.ts +29 -0
- package/dist/accessibility.js +258 -0
- package/dist/browser-actions.d.ts +21 -0
- package/dist/browser-actions.js +213 -0
- package/dist/browser-indicators.d.ts +23 -0
- package/dist/browser-indicators.js +69 -0
- package/dist/browser-profiles.d.ts +10 -0
- package/dist/browser-profiles.js +174 -0
- package/dist/browser.d.ts +11 -0
- package/dist/browser.js +2071 -0
- package/dist/capture.d.ts +74 -0
- package/dist/capture.js +199 -0
- package/dist/client.d.ts +38 -0
- package/dist/client.js +331 -0
- package/dist/desktop.d.ts +20 -0
- package/dist/desktop.js +42 -0
- package/dist/extension.d.ts +4 -0
- package/dist/extension.js +409 -0
- package/dist/launcher.d.ts +6 -0
- package/dist/launcher.js +85 -0
- package/dist/native.d.ts +11 -0
- package/dist/native.js +145 -0
- package/dist/ocr.d.ts +52 -0
- package/dist/ocr.js +246 -0
- package/dist/ownership.d.ts +4 -0
- package/dist/ownership.js +24 -0
- package/dist/pointer.d.ts +108 -0
- package/dist/pointer.js +174 -0
- package/dist/protocol.d.ts +15 -0
- package/dist/protocol.js +1 -0
- package/dist/runtime.d.ts +8 -0
- package/dist/runtime.js +72 -0
- package/dist/settings.d.ts +85 -0
- package/dist/settings.js +449 -0
- package/dist/stop.d.ts +24 -0
- package/dist/stop.js +156 -0
- package/dist/text.d.ts +100 -0
- package/dist/text.js +183 -0
- package/dist/waits.d.ts +19 -0
- package/dist/waits.js +262 -0
- package/dist/window-management.d.ts +25 -0
- package/dist/window-management.js +167 -0
- package/dist/worker.d.ts +1 -0
- package/dist/worker.js +540 -0
- package/docs/README.md +54 -0
- package/docs/adr/0001-preserve-reference-behavior.md +9 -0
- package/docs/adr/0002-window-lifetime-references.md +11 -0
- package/docs/adr/0003-exclusive-desktop-control.md +11 -0
- package/docs/adr/0004-pi-first-acceptance.md +9 -0
- package/docs/adr/0005-default-apps-and-workspace-reuse.md +7 -0
- package/docs/agents/domain.md +9 -0
- package/docs/agents/issue-tracker.md +10 -0
- package/docs/agents/triage-labels.md +9 -0
- package/docs/browser.md +113 -0
- package/docs/implementation-plan.md +139 -0
- package/docs/indicators.md +53 -0
- package/docs/native-interop-research.md +17 -0
- package/docs/ownership.md +25 -0
- package/docs/pi-extension-research.md +57 -0
- package/docs/pointer.md +65 -0
- package/docs/runtime.md +42 -0
- package/docs/settings.md +33 -0
- package/docs/spec.md +161 -0
- package/docs/stopping.md +83 -0
- package/docs/text.md +79 -0
- package/docs/tickets.md +84 -0
- package/docs/validation.md +1372 -0
- package/docs/windows.md +171 -0
- package/package.json +134 -4
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { win32 } from "node:path";
|
|
2
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
3
|
+
import { retireDesktop } from "./desktop.js";
|
|
4
|
+
import { nativeDesktop } from "./native.js";
|
|
5
|
+
const target = {
|
|
6
|
+
windowRef: { type: "string", minLength: 1 },
|
|
7
|
+
windowTitle: { type: "string" },
|
|
8
|
+
processId: { type: "integer", minimum: 1 },
|
|
9
|
+
nativeWindowHandle: { type: "integer", minimum: 1 },
|
|
10
|
+
activate: { type: "boolean", default: false },
|
|
11
|
+
};
|
|
12
|
+
const definitions = {
|
|
13
|
+
launch_app: {
|
|
14
|
+
properties: {
|
|
15
|
+
target: { type: "string", minLength: 1, maxLength: 32767 },
|
|
16
|
+
arguments: { type: "string", maxLength: 32767, default: "" },
|
|
17
|
+
workingDirectory: { type: "string", maxLength: 32767, default: "" },
|
|
18
|
+
activate: { type: "boolean", default: false },
|
|
19
|
+
resolveOnly: { type: "boolean", default: false },
|
|
20
|
+
waitMs: { type: "integer", minimum: 0, maximum: 10000, default: 1500 },
|
|
21
|
+
},
|
|
22
|
+
required: ["target"],
|
|
23
|
+
},
|
|
24
|
+
activate_window: { properties: { ...target } },
|
|
25
|
+
move_window: {
|
|
26
|
+
properties: {
|
|
27
|
+
...target,
|
|
28
|
+
x: { type: "integer", minimum: -2147483648, maximum: 2147483647 },
|
|
29
|
+
y: { type: "integer", minimum: -2147483648, maximum: 2147483647 },
|
|
30
|
+
},
|
|
31
|
+
required: ["x", "y"],
|
|
32
|
+
},
|
|
33
|
+
close_window: { properties: { ...target } },
|
|
34
|
+
};
|
|
35
|
+
export const windowTools = Object.entries(definitions).map(([action, definition]) => ({
|
|
36
|
+
action,
|
|
37
|
+
parameters: {
|
|
38
|
+
type: "object",
|
|
39
|
+
additionalProperties: false,
|
|
40
|
+
...definition,
|
|
41
|
+
...(["activate_window", "close_window"].includes(action)
|
|
42
|
+
? {
|
|
43
|
+
properties: {
|
|
44
|
+
...definition.properties,
|
|
45
|
+
browserTab: { type: "string", minLength: 1 },
|
|
46
|
+
},
|
|
47
|
+
}
|
|
48
|
+
: {}),
|
|
49
|
+
},
|
|
50
|
+
}));
|
|
51
|
+
const hosts = new Set([
|
|
52
|
+
"cmd",
|
|
53
|
+
"powershell",
|
|
54
|
+
"pwsh",
|
|
55
|
+
"wt",
|
|
56
|
+
"wsl",
|
|
57
|
+
"bash",
|
|
58
|
+
"conhost",
|
|
59
|
+
"wscript",
|
|
60
|
+
"cscript",
|
|
61
|
+
"mshta",
|
|
62
|
+
"rundll32",
|
|
63
|
+
"regsvr32",
|
|
64
|
+
"msiexec",
|
|
65
|
+
"forfiles",
|
|
66
|
+
"schtasks",
|
|
67
|
+
]);
|
|
68
|
+
const controls = (value) => [...value].some((character) => character.charCodeAt(0) < 32);
|
|
69
|
+
export async function manageWindow(action, input, signal) {
|
|
70
|
+
const definition = definitions[action];
|
|
71
|
+
const invalid = (message) => ({
|
|
72
|
+
ok: false,
|
|
73
|
+
action,
|
|
74
|
+
error: `INVALID_ARGUMENTS: ${message}`,
|
|
75
|
+
});
|
|
76
|
+
if (!definition)
|
|
77
|
+
return invalid("unknown window action");
|
|
78
|
+
const args = {};
|
|
79
|
+
for (const key of Object.keys(input))
|
|
80
|
+
if (!(key in definition.properties))
|
|
81
|
+
return invalid(`unknown option ${key}`);
|
|
82
|
+
for (const [key, rule] of Object.entries(definition.properties)) {
|
|
83
|
+
const value = Object.hasOwn(input, key) ? input[key] : rule.default;
|
|
84
|
+
if (value === undefined) {
|
|
85
|
+
if (definition.required?.includes(key))
|
|
86
|
+
return invalid(`${key} is required`);
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (rule.type === "integer"
|
|
90
|
+
? !Number.isSafeInteger(value)
|
|
91
|
+
: typeof value !== rule.type)
|
|
92
|
+
return invalid(`invalid ${key}`);
|
|
93
|
+
if (typeof value === "number" &&
|
|
94
|
+
((rule.minimum !== undefined && value < rule.minimum) ||
|
|
95
|
+
(rule.maximum !== undefined && value > rule.maximum)))
|
|
96
|
+
return invalid(`${key} outside bounds`);
|
|
97
|
+
if (typeof value === "string") {
|
|
98
|
+
const length = [...value].length;
|
|
99
|
+
if ((rule.minLength !== undefined && length < rule.minLength) ||
|
|
100
|
+
(rule.maxLength !== undefined && length > rule.maxLength))
|
|
101
|
+
return invalid(`${key} outside bounds`);
|
|
102
|
+
}
|
|
103
|
+
if (typeof value === "string" &&
|
|
104
|
+
["target", "windowTitle", "windowRef"].includes(key) &&
|
|
105
|
+
!value.trim())
|
|
106
|
+
return invalid(`${key} cannot be empty`);
|
|
107
|
+
args[key] = value;
|
|
108
|
+
}
|
|
109
|
+
if (action !== "launch_app" &&
|
|
110
|
+
args.windowRef === undefined &&
|
|
111
|
+
args.windowTitle === undefined &&
|
|
112
|
+
args.processId === undefined &&
|
|
113
|
+
args.nativeWindowHandle === undefined)
|
|
114
|
+
return invalid("provide an explicit window target");
|
|
115
|
+
if (action === "launch_app") {
|
|
116
|
+
if (controls(String(args.target)) ||
|
|
117
|
+
controls(String(args.workingDirectory)) ||
|
|
118
|
+
/[\r\n]/u.test(String(args.arguments)) ||
|
|
119
|
+
String(args.arguments).includes(String.fromCharCode(0)))
|
|
120
|
+
return invalid("launch values must be single-line strings without control characters");
|
|
121
|
+
const name = win32
|
|
122
|
+
.basename(String(args.target).trim())
|
|
123
|
+
.replace(/\.(?:exe|com)$/iu, "")
|
|
124
|
+
.toLowerCase();
|
|
125
|
+
if (hosts.has(name) && String(args.arguments).trim())
|
|
126
|
+
return {
|
|
127
|
+
ok: false,
|
|
128
|
+
action,
|
|
129
|
+
error: `LAUNCH_COMMAND_REFUSED: ${name} accepts no arguments through launch_app; use Pi's shell tool for commands`,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
signal?.throwIfAborted();
|
|
133
|
+
try {
|
|
134
|
+
const before = action === "launch_app" && !args.resolveOnly
|
|
135
|
+
? await nativeDesktop.execute("list_windows", { maxWindows: 1000, includeInvisible: false, _metadataOnly: true }, signal)
|
|
136
|
+
: undefined;
|
|
137
|
+
const result = await nativeDesktop.execute(action, args, signal);
|
|
138
|
+
signal?.throwIfAborted();
|
|
139
|
+
if (!result.ok && String(result.error).includes("LAUNCH_PENDING_TIMEOUT"))
|
|
140
|
+
await retireDesktop();
|
|
141
|
+
if (action === "launch_app" && !args.resolveOnly && result.ok) {
|
|
142
|
+
if (Number(args.waitMs) > 0)
|
|
143
|
+
await delay(Number(args.waitMs), undefined, { signal });
|
|
144
|
+
const after = await nativeDesktop.execute("list_windows", { maxWindows: 1000, includeInvisible: false, _metadataOnly: true }, signal);
|
|
145
|
+
const prior = new Set(Array.isArray(before?.windows)
|
|
146
|
+
? before.windows.map((window) => window.nativeWindowHandle)
|
|
147
|
+
: []);
|
|
148
|
+
result.observedNewWindows =
|
|
149
|
+
after.ok && Array.isArray(after.windows)
|
|
150
|
+
? after.windows.filter((window) => !prior.has(window.nativeWindowHandle))
|
|
151
|
+
: [];
|
|
152
|
+
if (!before?.ok || !after.ok || before.truncated || after.truncated)
|
|
153
|
+
result.observationWarning =
|
|
154
|
+
"Window enumeration was incomplete; new-window observations are not exhaustive.";
|
|
155
|
+
}
|
|
156
|
+
return result;
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
if (signal?.aborted)
|
|
160
|
+
throw error;
|
|
161
|
+
return {
|
|
162
|
+
ok: false,
|
|
163
|
+
action,
|
|
164
|
+
error: error instanceof Error ? error.message : String(error),
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
}
|
package/dist/worker.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|