Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions dist/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ if (peekaboo?.state.version !== "4.8.0" || peekaboo.state.revision !== revision)
const checkout = dependencies.get("peekaboo");
if (!checkout)
throw new Error("The resolved Peekaboo checkout is missing");
const git = ["git", "-C", join(checkouts, checkout)];
const checkoutPath = join(checkouts, checkout);
const git = ["git", "-C", checkoutPath];
const head = spawn([...git, "rev-parse", "HEAD"]);
if (head.status !== 0 || head.stdout.trim() !== revision) {
throw new Error(`The Peekaboo checkout must be at ${revision} before applying the patches`);
Expand Down Expand Up @@ -122,15 +123,15 @@ try {
}
if (applied < 0) {
// The checkout is build scratch; an earlier revision of an existing patch leaves no valid prefix.
console.error("Restoring the native checkout, which matches no pinned patch prefix.");
console.error(`Restoring the native checkout at ${checkoutPath}, which matches no pinned patch prefix. Local edits there are discarded.`);
run([...git, "checkout", "--", "."]);
run([...git, "clean", "-fdq"]);
applied = 0;
}
for (const patch of patches.slice(applied))
run([...git, "apply", patch]);
if (!isExpected())
throw new Error("The native checkout differs from the pinned patch stack.");
throw new Error(`The native checkout at ${checkoutPath} differs from the pinned patch stack.`);
}
finally {
rmSync(temporary, { recursive: true, force: true });
Expand Down
2 changes: 1 addition & 1 deletion docs/build.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ The build:

1. Resolves only the versions in `Package.resolved`.
2. Checks Peekaboo's pinned revision.
3. Assembles the ordered patch stack in a private Git index and applies only the missing suffix. Drift from every complete prefix fails the build instead of producing unexpected source.
3. Assembles the ordered patch stack in a private Git index and applies only the missing suffix. The checkout under `<scratch>/checkouts/Peekaboo` is build scratch: when it matches no complete prefix, as after an earlier revision of a patch or a local edit, the build says so with its path, discards its local changes, and applies the whole stack. It still fails if the result differs from the stack. Keep Peekaboo edits you want in a patch, not in the checkout.
4. Builds in release mode.

`--out` receives `libDesktopTools.dylib`, `desktop-tools-client`, `desktop-tools-app` (the [Desktop Tools app](app.md) host), and `Licenses/<dependency>/` notices for this package and every resolved pin. Existing files in `<out>/Licenses` are kept.
Expand Down
2 changes: 1 addition & 1 deletion docs/tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ A status item is pressed through Accessibility in its owner process without movi
| `desktop_dialog_answer` | Press one dialog button by its exact title, replace one dialog text field's value, or choose a path in an Open or Save panel |
| `desktop_clipboard_write` | Replace the clipboard with text, an image, or file references |

Pointer input is delivered to the exact window without moving the physical pointer, except for `desktop_hover` and a `desktop_drag` with `to_snapshot` or `modifiers`. Hover effects follow the real pointer, so it moves the user's pointer and leaves it there. Before moving, it checks that the snapshot's window is still at the same place and frontmost at the point, and refuses otherwise. Afterward, it checks that the pointer arrived and the window is still frontmost there; if either can't be confirmed, the result is `unknown`. A drag into another window or app can't stay inside one window, so it also uses the real pointer, and pressing in the source may bring its app forward. Pass the destination's snapshot as `to_snapshot`. Both points must be uncovered at their snapshot positions, or the drag is refused before input. The pointer rests on the start point, then presses, pauses, moves, rests over the destination and releases. The result is always `unknown`; inspect both windows to see whether the drop happened. A drag with `modifiers`, such as Option to copy or Command to move in Finder, or Shift to constrain, holds the real keys system-wide from before the press until after the release, so it takes the same foreground route even within one window, and its result is `unknown` too. A `path` adds up to 16 points visited in order in straight segments; it works in both routes within one window but not with `to_snapshot`. `desktop_press` holds the button through the same exact-window route as a drag, and the host always releases it, even when the call is interrupted or the window changes. When the host turns on the agent cursor, an orange arrow first glides to each click, scroll, drag, hover or press point, about a third of a second before the input is sent. It then shows a ripple for clicks, chevrons for scrolls and a trail for drags. For a press, it stays squeezed until the button is released, then ripples. The cursor fades after a few seconds idle. The cursor never takes clicks or focus and is left out of `desktop_inspect` and `desktop_screen` captures. It is decoration only: if it fails or is slow, input proceeds unchanged after at most 600 ms. Keyboard input, `desktop_type` and `desktop_select` don't show it.
Pointer input is delivered to the exact window without moving the physical pointer, except for `desktop_hover` and a `desktop_drag` with `to_snapshot` or `modifiers`. Hover effects follow the real pointer, so it moves the user's pointer and leaves it there. Before moving, it checks that the snapshot's window is still at the same place and frontmost at the point, and refuses otherwise. Afterward, it checks that the pointer arrived and the window is still frontmost there; if either can't be confirmed, the result is `unknown`. A drag into another window or app can't stay inside one window, so it also uses the real pointer, and pressing in the source may bring its app forward. Pass the destination's snapshot as `to_snapshot`. Both points must be uncovered at their snapshot positions, or the drag is refused before input. The pointer rests on the start point, then presses, pauses, moves, rests over the destination and releases. The result is always `unknown`; inspect both windows to see whether the drop happened. A drag with `modifiers`, such as Option to copy or Command to move in Finder, or Shift to constrain, holds the real keys system-wide from before the press until after the release, so it takes the same foreground route even within one window, and its result is `unknown` too. Don't drag a window's title bar or edge to move or resize it: such a drag may be delivered without moving the window, and nothing reads the bounds back. Use `desktop_move` and `desktop_resize`, which set the window's bounds directly. A `path` adds up to 16 points visited in order in straight segments; it works in both routes within one window but not with `to_snapshot`. `desktop_press` holds the button through the same exact-window route as a drag, and the host always releases it, even when the call is interrupted or the window changes. When the host turns on the agent cursor, an orange arrow first glides to each click, scroll, drag, hover or press point, about a third of a second before the input is sent. It then shows a ripple for clicks, chevrons for scrolls and a trail for drags. For a press, it stays squeezed until the button is released, then ripples. The cursor fades after a few seconds idle. The cursor never takes clicks or focus and is left out of `desktop_inspect` and `desktop_screen` captures. It is decoration only: if it fails or is slow, input proceeds unchanged after at most 600 ms. Keyboard input, `desktop_type` and `desktop_select` don't show it.

When the host turns on the window highlight, the window an inspection or action targets gets an orange outline and a label such as "Claude is using TextEdit". It shows from the moment the request reaches the host, moves to a new window when the target changes, and fades about four seconds after the last request. The outline follows the window as it moves or resizes and stays directly above it in the window order, so windows in front of the target also cover the outline. It hides while the window is minimized, off screen or on another Space. Like the cursor, it never takes clicks or focus and is left out of captures. Requests without one exact window, such as `desktop_screen`, menus or the clipboard, don't show it.

Expand Down
9 changes: 6 additions & 3 deletions src/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ if (peekaboo?.state.version !== "4.8.0" || peekaboo.state.revision !== revision)
}
const checkout = dependencies.get("peekaboo");
if (!checkout) throw new Error("The resolved Peekaboo checkout is missing");
const git = ["git", "-C", join(checkouts, checkout)];
const checkoutPath = join(checkouts, checkout);
const git = ["git", "-C", checkoutPath];
const head = spawn([...git, "rev-parse", "HEAD"]);
if (head.status !== 0 || head.stdout.trim() !== revision) {
throw new Error(`The Peekaboo checkout must be at ${revision} before applying the patches`);
Expand Down Expand Up @@ -126,13 +127,15 @@ try {
}
if (applied < 0) {
// The checkout is build scratch; an earlier revision of an existing patch leaves no valid prefix.
console.error("Restoring the native checkout, which matches no pinned patch prefix.");
console.error(
`Restoring the native checkout at ${checkoutPath}, which matches no pinned patch prefix. Local edits there are discarded.`,
);
run([...git, "checkout", "--", "."]);
run([...git, "clean", "-fdq"]);
applied = 0;
}
for (const patch of patches.slice(applied)) run([...git, "apply", patch]);
if (!isExpected()) throw new Error("The native checkout differs from the pinned patch stack.");
if (!isExpected()) throw new Error(`The native checkout at ${checkoutPath} differs from the pinned patch stack.`);
} finally {
rmSync(temporary, { recursive: true, force: true });
}
Expand Down
Loading