@vashp2029/glovebox 0.3.0 → 0.3.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.1 (2026-11-03)
4
+
5
+ - Fix: the drawn agent cursor now glides to every action. Its animation never
6
+ moved the window, so it froze after the first action, and launching the helper
7
+ hidden could keep it from appearing at all.
8
+ - Add a demo to the README.
9
+
3
10
  ## 0.3.0 (2026-11-03)
4
11
 
5
12
  - First npm release, as `@vashp2029/glovebox`. CI runs the unit tests on every
package/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
  **Computer use for coding agents on macOS: one JavaScript call per step,
9
9
  accessibility diffs instead of screenshots, and your screen stays yours.**
10
10
 
11
- <!-- demo: docs/demo.gif goes here once recorded -->
11
+ ![Someone browses Wikipedia in Safari while an agent works Calculator and types the result into TextEdit in the background](https://raw.githubusercontent.com/vpatel9202/glovebox/main/media/demo.gif)
12
12
 
13
13
  ```js
14
14
  const calc = await gb.getApp("Calculator");
@@ -164,8 +164,10 @@ OpenAI's actual runtime and already have the ChatGPT app (lcu).
164
164
  The first time a session touches an app, you get a dialog: Allow for This
165
165
  Session, Always Allow, or Deny. Terminals, password managers, System Settings,
166
166
  and a few others are blocked unless you run `glovebox allow <bundle id>`; the
167
- list is in [SECURITY.md](SECURITY.md#blocked-apps). Switching to another app
168
- stops a running script (Escape too, with Input Monitoring). Every action is
167
+ list is in [SECURITY.md](SECURITY.md#blocked-apps). A script that had to bring
168
+ an app forward stops if you switch away. Scripts running in the background keep
169
+ going while you use other apps, and Escape stops any script if you grant Input
170
+ Monitoring. Every action is
169
171
  logged to `~/.glovebox/actions.log`.
170
172
 
171
173
  An approved app is approved for everything in it: allowing a browser lets the
package/SECURITY.md CHANGED
@@ -14,10 +14,12 @@ computer. Treat it with the same care as giving someone remote control.
14
14
  (see the list below). An agent with terminal access could otherwise use the
15
15
  GUI to run commands its sandbox would not allow. An app on the `deny` list
16
16
  is refused even if it is also allowed.
17
- - **Taking over stops a script.** If you switch to another app while a
18
- script is driving one, the script stops instead of taking focus back. With
19
- the optional Input Monitoring permission, pressing Escape also stops it
20
- (glovebox marks its own key events, so its own Escapes do not count).
17
+ - **Taking over stops a script.** If a script had to bring an app forward and
18
+ you switch away, the script stops instead of taking focus back. A script
19
+ working in the background keeps running while you use other apps, so switching
20
+ apps does not stop it. With the optional Input Monitoring permission, pressing
21
+ Escape stops any script (glovebox marks its own key events, so its own Escapes
22
+ do not count).
21
23
  - **Menu-bar item.** While an agent is connected, Glovebox Helper shows a
22
24
  menu-bar item listing each session and its approved apps. Stop Running
23
25
  Scripts stops every running script. Revoke Session Approvals clears the
package/docs/api.md CHANGED
@@ -119,10 +119,11 @@ windows).
119
119
 
120
120
  The first time a session touches an app, the user sees a dialog: Allow for
121
121
  This Session, Always Allow, or Deny. Terminals, password managers, and System
122
- Settings are blocked unless the user runs `glovebox allow <app>`. If the user
123
- switches to another app while a script runs, the script stops with a
124
- "Stopped: ..." message. Escape stops it too, but only when the user has
125
- granted Input Monitoring. Do not continue GUI work until the user asks.
122
+ Settings are blocked unless the user runs `glovebox allow <app>`. If a script
123
+ brought an app forward and the user switches away, the script stops with a
124
+ "Stopped: ..." message. Background scripts keep running while the user works in
125
+ other apps. Escape stops any script, but only when the user has granted Input
126
+ Monitoring. Do not continue GUI work until the user asks.
126
127
  On the foreground route a script brings an app forward at most once per call.
127
128
  Every action is appended to `~/.glovebox/actions.log` (typed text is logged
128
129
  as a length only).
@@ -134,6 +135,9 @@ as a length only).
134
135
  word you type can land in its field. Keep the time the menu is open short: open
135
136
  it and pick the item in one script, with no read in between. A dedicated
136
137
  `app.select(popup, item)` is planned.
138
+ - **Window controls during background typing.** A target window can show active
139
+ window controls while it receives background keys, even though your app stays
140
+ frontmost and keeps your keyboard.
137
141
  - **One-node trees.** Remote desktops such as Citrix expose a single accessibility
138
142
  node, so work there runs on screenshots and pixel clicks.
139
143
 
package/docs/design.md CHANGED
@@ -158,8 +158,8 @@ Computer use can click anything, so approval is part of the product:
158
158
  Editor, Automator, and the helper itself are blocked by default and never
159
159
  offered in a dialog. Only an explicit `glovebox allow` unlocks one. The
160
160
  full list is in `SECURITY.md`.
161
- - Switching to another app stops the running script. A script brings an app
162
- forward at most once per call; if the app is no longer in front later in
161
+ - Switching away stops a script on the foreground route; background scripts
162
+ keep running. A script brings an app forward at most once per call; if the app is no longer in front later in
163
163
  the same call, the user took over, and the script stops rather than taking
164
164
  focus back. (An earlier version re-activated before every key and fought
165
165
  the user for focus.)
@@ -20,7 +20,7 @@ import Foundation
20
20
  import ScreenCaptureKit
21
21
  import UniformTypeIdentifiers
22
22
 
23
- let helperVersion = "0.2.0"
23
+ let helperVersion = "0.3.1"
24
24
  // Marks events we synthesize so the Escape watcher ignores them.
25
25
  let syntheticMarker: Int64 = 0x676C_6F76
26
26
 
@@ -1078,26 +1078,33 @@ final class AgentCursor {
1078
1078
  // Blocks until the move animation finishes so the action lines up with it.
1079
1079
  func move(to point: CGPoint, above windowId: Int?) {
1080
1080
  guard enabled else { return }
1081
+ var from = NSPoint.zero
1082
+ var target = NSPoint.zero
1081
1083
  var duration: TimeInterval = 0
1082
1084
  DispatchQueue.main.sync {
1083
1085
  let w = self.window ?? self.makeWindow()
1084
1086
  self.window = w
1085
1087
  guard let primary = NSScreen.screens.first else { return }
1086
1088
  // AppKit frames are bottom-left origin; the arrow tip is the frame's top-left.
1087
- let target = NSPoint(x: point.x - 4, y: primary.frame.height - point.y - self.size.height + 3)
1088
- let from = w.isVisible ? w.frame.origin : target
1089
+ target = NSPoint(x: point.x - 4, y: primary.frame.height - point.y - self.size.height + 3)
1090
+ from = w.isVisible ? w.frame.origin : target
1089
1091
  let distance = hypot(target.x - from.x, target.y - from.y)
1090
1092
  duration = w.isVisible ? min(0.45, 0.12 + Double(distance) / 2400) : 0
1091
1093
  if let id = windowId { w.order(.above, relativeTo: id) } else { w.orderFrontRegardless() }
1092
- NSAnimationContext.runAnimationGroup { ctx in
1093
- ctx.duration = duration
1094
- ctx.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
1095
- w.animator().setFrameOrigin(target)
1096
- }
1094
+ if duration == 0 { w.setFrameOrigin(target) }
1097
1095
  self.hideTimer?.invalidate()
1098
1096
  self.hideTimer = Timer.scheduledTimer(withTimeInterval: 4, repeats: false) { _ in self.hide() }
1099
1097
  }
1100
- if duration > 0 { usleep(useconds_t(duration * 1_000_000)) }
1098
+ guard duration > 0 else { return }
1099
+ // Stepped by hand: an animator() frame move left the window where it was.
1100
+ let steps = max(1, Int(duration * 60))
1101
+ for step in 1...steps {
1102
+ let t = Double(step) / Double(steps)
1103
+ let eased = t * t * (3 - 2 * t)
1104
+ let next = NSPoint(x: from.x + (target.x - from.x) * eased, y: from.y + (target.y - from.y) * eased)
1105
+ DispatchQueue.main.sync { self.window?.setFrameOrigin(next) }
1106
+ usleep(useconds_t(duration / Double(steps) * 1_000_000))
1107
+ }
1101
1108
  }
1102
1109
 
1103
1110
  func hide() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vashp2029/glovebox",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Computer use for coding agents on macOS: one JavaScript call per step, accessibility diffs instead of screenshots, input in the background. MCP and CLI.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/config.mjs CHANGED
@@ -4,7 +4,7 @@ import fs from "node:fs";
4
4
  import os from "node:os";
5
5
  import path from "node:path";
6
6
 
7
- export const VERSION = "0.3.0";
7
+ export const VERSION = "0.3.1";
8
8
 
9
9
  export function homeDir() {
10
10
  return process.env.GLOVEBOX_HOME || path.join(os.homedir(), ".glovebox");
@@ -135,7 +135,7 @@ export async function build({ log = () => {} } = {}) {
135
135
 
136
136
  // Starts the helper through LaunchServices so it is its own responsible process.
137
137
  export async function launch({ requestPermissions = false } = {}) {
138
- const args = ["-g", "-j", "-a", appPath()];
138
+ const args = ["-g", "-a", appPath()]; // Not -j: a hidden app cannot show the agent cursor.
139
139
  for (const name of ["GLOVEBOX_HOME", "GLOVEBOX_APPROVAL", "GLOVEBOX_SOCKET"]) {
140
140
  if (process.env[name]) args.push("--env", `${name}=${process.env[name]}`);
141
141
  }