junis 0.3.17 → 0.4.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/dist/cli/index.js CHANGED
@@ -570,6 +570,9 @@ var FilesystemTools = class {
570
570
  "- For reading files prefer read_file, for editing prefer edit_block, for searching prefer search_code.",
571
571
  "- NOT for macOS app GUI interaction. Use desktop_* tools instead: desktop_open_app, desktop_see, desktop_click, desktop_type, desktop_paste, desktop_hotkey, desktop_scroll, desktop_move, desktop_menu, desktop_screenshot.",
572
572
  "- Exception: permission fix commands (swift -e, peekaboo permissions, open 'x-apple.systempreferences:...').",
573
+ "- Exception: osascript coordinate queries \u2014 Use osascript via this tool to query exact UI element position and size before any click/move/drag operation.",
574
+ " Pattern: osascript + System Events \u2192 position + size \u2192 center = (x + w/2, y + h/2) \u2192 desktop_click(coords).",
575
+ " This is the ONLY reliable way to get pixel-accurate coordinates on macOS. NEVER estimate coords from screenshots.",
573
576
  "",
574
577
  "BEHAVIOR:",
575
578
  "- Execute commands directly when the user requests them. Do not ask for confirmation \u2014 the user has already decided.",
@@ -2101,19 +2104,8 @@ function checkBlacklist(app) {
2101
2104
  function json(data) {
2102
2105
  return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
2103
2106
  }
2104
- async function resolveElementCoords(query, app) {
2105
- if (!app) {
2106
- try {
2107
- const { stdout } = await execa("osascript", [
2108
- "-e",
2109
- 'tell application "System Events" to get name of first application process whose frontmost is true'
2110
- ]);
2111
- app = stdout.trim();
2112
- } catch {
2113
- return null;
2114
- }
2115
- }
2116
- const safeApp = app.replace(/[\\"]/g, "\\$&");
2107
+ async function searchProcessElements(processName, query) {
2108
+ const safeApp = processName.replace(/[\\"]/g, "\\$&");
2117
2109
  const safeQuery = query.replace(/[\\"]/g, "\\$&");
2118
2110
  const script = `
2119
2111
  tell application "System Events"
@@ -2158,6 +2150,26 @@ return "NOT_FOUND"
2158
2150
  return null;
2159
2151
  }
2160
2152
  }
2153
+ async function resolveElementCoords(query, app) {
2154
+ let targetApp = app;
2155
+ if (!targetApp) {
2156
+ try {
2157
+ const { stdout } = await execa("osascript", [
2158
+ "-e",
2159
+ 'tell application "System Events" to get name of first application process whose frontmost is true'
2160
+ ]);
2161
+ targetApp = stdout.trim();
2162
+ } catch {
2163
+ return null;
2164
+ }
2165
+ }
2166
+ const result = await searchProcessElements(targetApp, query);
2167
+ if (result) return result;
2168
+ if (targetApp !== "Dock") {
2169
+ return await searchProcessElements("Dock", query);
2170
+ }
2171
+ return null;
2172
+ }
2161
2173
  var DesktopTools = class {
2162
2174
  register(server) {
2163
2175
  server.tool(
@@ -2197,8 +2209,9 @@ var DesktopTools = class {
2197
2209
  "desktop_screenshot",
2198
2210
  [
2199
2211
  "Take a screenshot. Returns base64 image at logical resolution (matches click coordinate system 1:1).",
2200
- "Use for visual context or to verify UI state. Screenshot pixel coordinates map directly to desktop_click(coords).",
2201
- "For clicking, prefer desktop_click(query, app) which auto-resolves coordinates. Use screenshot coords as fallback."
2212
+ "Use for visual context or to verify UI state ONLY.",
2213
+ "WARNING: NEVER estimate click coordinates from screenshot images \u2014 visual estimation causes misclicks. Use desktop_click(query, app) for auto-resolution, or execute_command + osascript for exact coords.",
2214
+ "Do not use visual coordinates from this screenshot directly. Use execute_command + osascript to verify exact element position first."
2202
2215
  ].join("\n"),
2203
2216
  {
2204
2217
  app: z5.string().optional().describe("Capture specific app window"),
@@ -2237,9 +2250,10 @@ var DesktopTools = class {
2237
2250
  [
2238
2251
  "Click a UI element by text label (query), coordinates (coords), or element ID (on).",
2239
2252
  "BEST: Use query with app name \u2014 auto-resolves to exact screen coords via accessibility API. No desktop_see needed.",
2240
- "GOOD: Use coords 'x,y' from desktop_screenshot for pixel-perfect accuracy.",
2253
+ "GOOD: Use coords 'x,y' \u2014 MUST be from osascript position+size center calculation, NEVER from visual screenshot estimation.",
2254
+ "Before using coords, always query exact position via execute_command + osascript. Calculate center = position + size/2. Never estimate from screenshots.",
2241
2255
  "CAUTION: 'on' (element ID) has known offset bug \u2014 use coords or query instead when possible.",
2242
- "If not found, try: desktop_screenshot to find coords, desktop_menu for menu items, or desktop_hotkey for shortcuts.",
2256
+ "If query not found: use execute_command + osascript to get element position+size, then center = (x + w/2, y + h/2). Or try desktop_menu, desktop_hotkey.",
2243
2257
  "NOTE: Web page elements (inside browser) are invisible to desktop tools. Use browser_* tools instead."
2244
2258
  ].join("\n"),
2245
2259
  {
@@ -2305,6 +2319,7 @@ var DesktopTools = class {
2305
2319
  "desktop_paste",
2306
2320
  [
2307
2321
  "Paste via clipboard (Cmd+V). Atomic: saves clipboard \u2192 sets content \u2192 pastes \u2192 restores.",
2322
+ "IMPORTANT: Focus the target field first (click it with desktop_click) before pasting.",
2308
2323
  "Supports all Unicode (Korean, Japanese, Chinese, emoji). Use instead of desktop_type for non-ASCII.",
2309
2324
  "Can also paste file contents via filePath."
2310
2325
  ].join("\n"),
@@ -2387,7 +2402,10 @@ var DesktopTools = class {
2387
2402
  );
2388
2403
  server.tool(
2389
2404
  "desktop_move",
2390
- "Move mouse cursor without clicking. Use before scroll or to hover.",
2405
+ [
2406
+ "Move mouse cursor without clicking. Use before scroll or to hover.",
2407
+ "Before using coords, always query exact position via execute_command + osascript. Calculate center = position + size/2. Never estimate from screenshots."
2408
+ ].join("\n"),
2391
2409
  {
2392
2410
  coords: z5.string().optional().describe("Screen coordinates 'x,y'"),
2393
2411
  to: z5.string().optional().describe("Element text/label to move to"),
@@ -2422,7 +2440,8 @@ var DesktopTools = class {
2422
2440
  "desktop_drag",
2423
2441
  [
2424
2442
  "Drag and drop between elements or coordinates. Supports cross-app drag (e.g. file to Trash).",
2425
- "Use element IDs from desktop_see or raw coordinates."
2443
+ "Prefer fromCoords/toCoords for accuracy. Element IDs (from/to) have known offset bug.",
2444
+ "Before using fromCoords/toCoords, always query exact position via execute_command + osascript. Calculate center = position + size/2. Never estimate from screenshots."
2426
2445
  ].join("\n"),
2427
2446
  {
2428
2447
  from: z5.string().optional().describe("Source element ID from desktop_see"),
@@ -2619,6 +2638,7 @@ var DesktopTools = class {
2619
2638
  app: z5.string().optional().describe("App to open with")
2620
2639
  },
2621
2640
  async ({ url, app }) => {
2641
+ checkBlacklist(app);
2622
2642
  const args = ["open", url];
2623
2643
  if (app) args.push("--app", app);
2624
2644
  return json(await peekaboo(args));
@@ -86,6 +86,9 @@ var FilesystemTools = class {
86
86
  "- For reading files prefer read_file, for editing prefer edit_block, for searching prefer search_code.",
87
87
  "- NOT for macOS app GUI interaction. Use desktop_* tools instead: desktop_open_app, desktop_see, desktop_click, desktop_type, desktop_paste, desktop_hotkey, desktop_scroll, desktop_move, desktop_menu, desktop_screenshot.",
88
88
  "- Exception: permission fix commands (swift -e, peekaboo permissions, open 'x-apple.systempreferences:...').",
89
+ "- Exception: osascript coordinate queries \u2014 Use osascript via this tool to query exact UI element position and size before any click/move/drag operation.",
90
+ " Pattern: osascript + System Events \u2192 position + size \u2192 center = (x + w/2, y + h/2) \u2192 desktop_click(coords).",
91
+ " This is the ONLY reliable way to get pixel-accurate coordinates on macOS. NEVER estimate coords from screenshots.",
89
92
  "",
90
93
  "BEHAVIOR:",
91
94
  "- Execute commands directly when the user requests them. Do not ask for confirmation \u2014 the user has already decided.",
@@ -1617,19 +1620,8 @@ function checkBlacklist(app) {
1617
1620
  function json(data) {
1618
1621
  return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
1619
1622
  }
1620
- async function resolveElementCoords(query, app) {
1621
- if (!app) {
1622
- try {
1623
- const { stdout } = await execa("osascript", [
1624
- "-e",
1625
- 'tell application "System Events" to get name of first application process whose frontmost is true'
1626
- ]);
1627
- app = stdout.trim();
1628
- } catch {
1629
- return null;
1630
- }
1631
- }
1632
- const safeApp = app.replace(/[\\"]/g, "\\$&");
1623
+ async function searchProcessElements(processName, query) {
1624
+ const safeApp = processName.replace(/[\\"]/g, "\\$&");
1633
1625
  const safeQuery = query.replace(/[\\"]/g, "\\$&");
1634
1626
  const script = `
1635
1627
  tell application "System Events"
@@ -1674,6 +1666,26 @@ return "NOT_FOUND"
1674
1666
  return null;
1675
1667
  }
1676
1668
  }
1669
+ async function resolveElementCoords(query, app) {
1670
+ let targetApp = app;
1671
+ if (!targetApp) {
1672
+ try {
1673
+ const { stdout } = await execa("osascript", [
1674
+ "-e",
1675
+ 'tell application "System Events" to get name of first application process whose frontmost is true'
1676
+ ]);
1677
+ targetApp = stdout.trim();
1678
+ } catch {
1679
+ return null;
1680
+ }
1681
+ }
1682
+ const result = await searchProcessElements(targetApp, query);
1683
+ if (result) return result;
1684
+ if (targetApp !== "Dock") {
1685
+ return await searchProcessElements("Dock", query);
1686
+ }
1687
+ return null;
1688
+ }
1677
1689
  var DesktopTools = class {
1678
1690
  register(server) {
1679
1691
  server.tool(
@@ -1713,8 +1725,9 @@ var DesktopTools = class {
1713
1725
  "desktop_screenshot",
1714
1726
  [
1715
1727
  "Take a screenshot. Returns base64 image at logical resolution (matches click coordinate system 1:1).",
1716
- "Use for visual context or to verify UI state. Screenshot pixel coordinates map directly to desktop_click(coords).",
1717
- "For clicking, prefer desktop_click(query, app) which auto-resolves coordinates. Use screenshot coords as fallback."
1728
+ "Use for visual context or to verify UI state ONLY.",
1729
+ "WARNING: NEVER estimate click coordinates from screenshot images \u2014 visual estimation causes misclicks. Use desktop_click(query, app) for auto-resolution, or execute_command + osascript for exact coords.",
1730
+ "Do not use visual coordinates from this screenshot directly. Use execute_command + osascript to verify exact element position first."
1718
1731
  ].join("\n"),
1719
1732
  {
1720
1733
  app: z5.string().optional().describe("Capture specific app window"),
@@ -1753,9 +1766,10 @@ var DesktopTools = class {
1753
1766
  [
1754
1767
  "Click a UI element by text label (query), coordinates (coords), or element ID (on).",
1755
1768
  "BEST: Use query with app name \u2014 auto-resolves to exact screen coords via accessibility API. No desktop_see needed.",
1756
- "GOOD: Use coords 'x,y' from desktop_screenshot for pixel-perfect accuracy.",
1769
+ "GOOD: Use coords 'x,y' \u2014 MUST be from osascript position+size center calculation, NEVER from visual screenshot estimation.",
1770
+ "Before using coords, always query exact position via execute_command + osascript. Calculate center = position + size/2. Never estimate from screenshots.",
1757
1771
  "CAUTION: 'on' (element ID) has known offset bug \u2014 use coords or query instead when possible.",
1758
- "If not found, try: desktop_screenshot to find coords, desktop_menu for menu items, or desktop_hotkey for shortcuts.",
1772
+ "If query not found: use execute_command + osascript to get element position+size, then center = (x + w/2, y + h/2). Or try desktop_menu, desktop_hotkey.",
1759
1773
  "NOTE: Web page elements (inside browser) are invisible to desktop tools. Use browser_* tools instead."
1760
1774
  ].join("\n"),
1761
1775
  {
@@ -1821,6 +1835,7 @@ var DesktopTools = class {
1821
1835
  "desktop_paste",
1822
1836
  [
1823
1837
  "Paste via clipboard (Cmd+V). Atomic: saves clipboard \u2192 sets content \u2192 pastes \u2192 restores.",
1838
+ "IMPORTANT: Focus the target field first (click it with desktop_click) before pasting.",
1824
1839
  "Supports all Unicode (Korean, Japanese, Chinese, emoji). Use instead of desktop_type for non-ASCII.",
1825
1840
  "Can also paste file contents via filePath."
1826
1841
  ].join("\n"),
@@ -1903,7 +1918,10 @@ var DesktopTools = class {
1903
1918
  );
1904
1919
  server.tool(
1905
1920
  "desktop_move",
1906
- "Move mouse cursor without clicking. Use before scroll or to hover.",
1921
+ [
1922
+ "Move mouse cursor without clicking. Use before scroll or to hover.",
1923
+ "Before using coords, always query exact position via execute_command + osascript. Calculate center = position + size/2. Never estimate from screenshots."
1924
+ ].join("\n"),
1907
1925
  {
1908
1926
  coords: z5.string().optional().describe("Screen coordinates 'x,y'"),
1909
1927
  to: z5.string().optional().describe("Element text/label to move to"),
@@ -1938,7 +1956,8 @@ var DesktopTools = class {
1938
1956
  "desktop_drag",
1939
1957
  [
1940
1958
  "Drag and drop between elements or coordinates. Supports cross-app drag (e.g. file to Trash).",
1941
- "Use element IDs from desktop_see or raw coordinates."
1959
+ "Prefer fromCoords/toCoords for accuracy. Element IDs (from/to) have known offset bug.",
1960
+ "Before using fromCoords/toCoords, always query exact position via execute_command + osascript. Calculate center = position + size/2. Never estimate from screenshots."
1942
1961
  ].join("\n"),
1943
1962
  {
1944
1963
  from: z5.string().optional().describe("Source element ID from desktop_see"),
@@ -2135,6 +2154,7 @@ var DesktopTools = class {
2135
2154
  app: z5.string().optional().describe("App to open with")
2136
2155
  },
2137
2156
  async ({ url, app }) => {
2157
+ checkBlacklist(app);
2138
2158
  const args = ["open", url];
2139
2159
  if (app) args.push("--app", app);
2140
2160
  return json(await peekaboo(args));
@@ -87,6 +87,9 @@ var FilesystemTools = class {
87
87
  "- For reading files prefer read_file, for editing prefer edit_block, for searching prefer search_code.",
88
88
  "- NOT for macOS app GUI interaction. Use desktop_* tools instead: desktop_open_app, desktop_see, desktop_click, desktop_type, desktop_paste, desktop_hotkey, desktop_scroll, desktop_move, desktop_menu, desktop_screenshot.",
89
89
  "- Exception: permission fix commands (swift -e, peekaboo permissions, open 'x-apple.systempreferences:...').",
90
+ "- Exception: osascript coordinate queries \u2014 Use osascript via this tool to query exact UI element position and size before any click/move/drag operation.",
91
+ " Pattern: osascript + System Events \u2192 position + size \u2192 center = (x + w/2, y + h/2) \u2192 desktop_click(coords).",
92
+ " This is the ONLY reliable way to get pixel-accurate coordinates on macOS. NEVER estimate coords from screenshots.",
90
93
  "",
91
94
  "BEHAVIOR:",
92
95
  "- Execute commands directly when the user requests them. Do not ask for confirmation \u2014 the user has already decided.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "junis",
3
- "version": "0.3.17",
3
+ "version": "0.4.0",
4
4
  "description": "One-line device control for AI agents",
5
5
  "type": "module",
6
6
  "bin": {